Background:
I am creating a three tier e commerce website which sells books. Within my website I have created a form (only accessible to staff members) which allows the staff member to add a new book to the system (the database).
At the moment I have a table within my database which records the following data:
book_isdn // unique identifier of each book.
book_cat
book_title
book_author
etc..
Along with this, I have created a table for book categories which stores the following:
cat_id
cat_title
I have defined the following rows in the categories table:
cat_id 1 = Business books
cat_id 2 = Computing books
cat_id 3 = Science books
cat_id 4 = History books
etc
The problem:
In the form which allows a staff member to add a new book, I have a list:
<select multiple name="b_category" style = "width:150px" required>
<?php
$get_cats = "select * from categories";
$run_cats = mysqli_query($connect, $get_cats);
while ($row_cats = mysqli_fetch_array($run_cats)) {
$cat_id = $row_cats['cat_id'];
$cat_title = $row_cats['cat_title'];
echo "<option value='$cat_id'> $cat_title </option>";
}
?>
</select>
I want to add a new book to the 'books' table with the corresponding cat_id for the category to which the book belongs to (i.e. business, computing etc.).
However, a book can also be in two categories, i.e. a book can be both in the field of business and computing.
The question:
How can I alter the form so that it selects multiple options from and adds them to the database, along with the cat_id?
For example:
if using the form I complete all other fields and select computing and business from the list, I want it so that upon clicking "Add new book", the form data is sent to the 'books' table where I will be able to see the new book and under the field of book_cat, I will see 1,2.
I am completely stumped. Is there any way to approach this issue? I hope I have explained this well.
Thanks.
Ok, let's start with something you have not asked for.
a) DB design
Please do not store a concatenated id value like 1,2 in book_cat.
That makes lookups and search hard, because you need to fetch & split every single time. That might only work for really small systems.
What you are looking for is a relation table from books to categories.
Name it like this books_to_categories, with book_id and cat_id.
Query: SELECT cat_id FROM books_to_categories WHERE book_id = 2;
Result: array one or more ids, then resolve the cat_id to it's name (cat_title) via the category table.
The keyword here is database normalization.
b) Formular
Ok, you have a drop down list box, where you can do multiple selections.
Now, the values of these selections need to be transfered to the server side.
One trick is to use array syntax, instead of
<select name="b_category" size=4 multiple>
just use
<select name="b_category[]" size=4 multiple>
and on the server-side var_dump($_POST['b_category']); to see the values received. Then simply iterate over the values of the array and make your database entries.
Related
I created an html that has a formulary that let you choose between four different options:
<select name="especie">
<option value = "1"> Hyundai </option>
<option value = "2"> Renault </option>
<option value = "3"> Ford </option>
<option value = "4"> Fiat </option>
</select>
Each of these options correspond to one table in a mySQL database (let´s say it´s called companies), and have the same variables. The html then lets you perform the query, and I want it to display the information according to the table you have previously chosen.
$query = "SELECT * FROM $table WHERE brand LIKE ´%$brand%´;";
So what I want is to create a PHP that chooses dynamically the table ($table) depending on the chosen option by the user (in the first chuck of code).
Any help would be really appreciated it.
Without re designing your DB structure - which could be the best course of action, there are two easy ways to do this. You could do it basically the way you said. If choosing this method you need to make sure that the table is being selected by a key from an array of tables so it is a safe input like so:
$tables = ["table1" => "table1","table2" =>"table2"];
$query = "SELECT * FROM ".$tables[$table_key_from_input]." WHERE brand LIKE ´%$brand%´;";
But this is not ideal as, when tables are added removed all code like this needs to be updated.
Another way of getting the desired outcome would be to make a database view which is a union of all the tables (plus the table name in an extra column) then you can just select from the view every time using the table as a variable supplied by the user input.
You can learn about views here: https://www.w3schools.com/sql/sql_view.asp
And see how to make a union here: https://www.w3schools.com/sql/sql_union.asp
The view code would look a little like this:
CREATE VIEW view_name AS
SELECT *, 'table1' AS 'table' FROM table1
UNION
SELECT *, 'table2' AS 'table' FROM table2
Then your query would be like this:
$query = "SELECT * FROM view_name WHERE brand LIKE ´%$brand%´ AND table = $table;";
(But ideally using PDO!)
Also if you do it this way if you ever re think your db structure and perhaps do what was suggested by El_Vanja in the comments you can, and by deleting the view and giving the table the same name the code wouldn't even have to change!
I apologize for this beginner question but unfortunately it is my level.
I have a fairly simple web page for my work, it is a index.php page that when opened goes out to a DB and retrieves the contents of a certain column. It then places the results in a drop down pick list.
Here is my problem, this column is a list of materials for customers. Some customers have more than 1 different type of material, while others have one.
Therefore my pick list can look like:
Apple /n
Orange; Apple; banana/n
banana;peach /n
orange/n
I am trying to come up with something that when I pull the data from the mysql DB that my php seperates the materials and only provides unique items.
Here is my code for creating picklist:
<p><select size="1" name="material" ID="material" onChange="showfield(value);">
<option value=''><None></option>;
<?php
while ($row = mysql_fetch_array($query))
{
$rowmod = strtr($row['material']," ","_");
echo "<option value='$rowmod'>$row[material]</option>";
}
?>
Here is my mysql select:
$query="select distinct material from TABLE-A order by material";
Update:
I think my Mysql is right, I think I played around with the php strtr and I was able to remove the ; and add lines in, but now I do not know how to make it cycle through and create my
here is the new code:
$row[product]";
}
?>
some output from my $row will have only one product, some will have 2 or more, I wonder if I have to put another while loop after the $rowmod?
I have a feeling I am close, but hoping for some guidance.
First of all, you should make a material table, indexed with an auto_increment id, and use that ID in what you call TABLE-A in a column material_id. Like that you'll have a list of unique material in one table dedicated to it, where you can even add some columns for the details of the material, etc..
Then I am unsure of your needs/use-case, but it looks like you'll need a customer_material table to link a customer with its material(s) so that you know which customer uses which material. It would have an id auto-incremented, as it should always be for any table for better practices, a customer_id and a material_id, with an unique index on the both last columns (customer_id+material_id) to be sure you link one material to one customer only once and not many time each material for the same customer.
Then when you'll need to list the materials for a given customer, just use this query:
select m.id, m.name
from customer_material cm
join material m on cm.material_id = m.id
where cm.customer_id = YOUR_CUSTOMER_ID
If you need to list all materials uniquely, you;ll then need this query:
select m.id, m.name
from material m
order by m.name /* optional, to order by the material name */
And voila. As I am unsure of your use-case the schema of the DB might be a bit different, but I think anyway the main problem in your issue is that the DB is not well architected. Lemme know if I something is unclear here.
You mentioned that different customers have different materials, but that is not reflected in your SQL query because there is no WHERE clause, meaning that you are selecting all unique values from the materials table regardless of any condition. But with that aside, I think that if you change your code slightly you will get some data.
$query="select distinct `material` from `TABLE-A` order by material"
<p><select size="1" name="material" ID="material" onChange="showfield(value);">
<option value=''><None></option>;
<?php
while ($row = mysql_fetch_assoc($query))
{
$rowmod = strtr($row['material']," ","_");
echo "<option value='$rowmod'>$row['material']</option>";
}
?>
Im trying to create a checklist system eg. a list of items to collect. the user will be able to add the list to their profile and then as they collect the items then can check the box for an item in the list click submit and the checked item will now be marked as collected. I have it coded and working fine but it makes an insane amount of queries to the database to work.
i have 5 tables. a users table (for the registered users username, id..etc), a lists table (containing the list name, description, id ), a list items table (containing the individual items. id, title and listID (to reference the list it belongs to)). userslist table (for the lists the user has added to their profile. userID and listID) and collecteditems table (this has the list items that a person has checked the box for as collected. listItemsID, UserID)
the problem is when i view the mylists.php page it will query the userslist table and return all the ID's for the lists the user has added. then once i have the ID for the list it then queries the list table to find out what the name of the list is (this could mean having to make 10 queries to the list table if i have 10 different lists added). if i added a listname column to the userslist table i would only need to make 1 query for the page and that is to the userslists table and i could construct the page with that 1 query.
First, I wouldn't worry about queries on primary keys. All your tables have a primary key referenced by other tables. These will use joins.
Second, you don't have to get the list names separately. Use a query such as:
select l.listName
from UserLists ul join
Lists l
on ul.listId = l.listId
where userId = $userid
This will return all the names in a single query.
It sounds like you should keep your data normalized (that is, avoid the redundant data) and instead gather all the data you want in a single query, by using a JOIN.
I am making a music site on which there will be a CMS to add new songs, and the visitor can see/play the songs on the news feed or browse/search by artist/song. Songs are referred to as tracks from here on.
The database looks as follows:
tracks
id | title | artist | year | path_mp3 | path_ogg | date_time
artists
id | artist (I have this table because I'd like to add additional artist info later on.)
track2artist
track_id | artist_id
Some tracks have two or more artists, with those artists each having their own solo tracks as well. Therefore I'd like to keep these artists as separate entities so that users can browse to them accordingly, yet when applicable, show that multiple artists were responsible for the same song.
When I output a track on the news feed that has multiple artists, I would like to link to a page which grabs only tracks which both artists contributed to, and from that page, if the visitor clicks one of the artists, to go to the individual artist page.
http://www.discogs.com/search?q=cid+inc+and+victor+hugo&type=all
For example, if you click this link and choose the top search result, you can see the effect I'm looking for. The artist links are separate on the landing page.
What I'm getting with my current code is that tracks that have multiple entries in the track2artist table (by having multiple artists), are getting displayed multiple times. I would like each track to occur only once, yet have it still be known if there are multiple artists, and what their ids are.
I have tried including the "group by tracks.id" at the end of the sql statement, which does in fact select each statement only once. However, this fails to pick up any multiple artist_id entries in track2artist, so I have no way of passing these multiple artist ids when the user clicks.
Would I need new SQL syntax or is it in my PHP? I am trying to get away with as few database calls as possible, as I know that's what is recommended.
I appreciate any help on this. This is possibly covered elsewhere, but when searching, I was rather confused when trying to understand other examples. Thanks for taking the time to read this.
$conn = dbConnect('read');
$sql = "SELECT * FROM tracks INNER JOIN track2artist ON tracks.id = track2artist.track_id";
$result = $conn->query($sql) or die (mysqli_error($conn));
?>
<table id="feed">
<?php
while($track = $result->fetch_assoc()) {
?>
<tr>
<td><a href="javascript:;" id="playlist-add-track-id-<?php echo $track['id']; ?>">
<img src="/assets/img/add_track.gif" class="add_track_icon"></a></td>
<td><?php echo $track['title']; ?> by <a href="/?page=artist&artist_id=<?php echo $track['artist_id']; ?>">
<?php echo $track['artist']; ?></a></td>
</tr>
<?php } ?>
</table>
use the DISTINCT keyword, which will not return duplicates when joining.
$sql = "SELECT DISTINCT * FROM tracks INNER JOIN track2artist ON tracks.id = track2artist.track_id";
since you have songs with multiple authors in a different table you are going to have the tracks listed more then once. [once for each piece of data that makes the row different]
what you want returned is something like this
track artist
artist
artist
track artist
artist
track artist
track artist
however mysql will only return FULL ROWS meaning for each piece of data it will return a complete row of information. to keep queries low it is best to group the information after the database has returned the info.
I would say instead of outputting right away, put this as your database parse loop
<?php
while($track = $result->fetch_assoc()) {
$tracklist[$track['id']]['title'] = $track['title'];
$tracklist[$track['id']]['artists'][$track['artist_id']] = $track['artist'];
}
this will crunch your array into the format you are expecting to find, btw, you will also have to iterate over the artists array with in the track array to display all the artists associated with each track.
How could I create a list in php of categories and types of topics that are mixed together?
Meaning, the list should look like this:
Sports (this is a category)
Soccer (this is a type)
Golf (this is a type)
Basketball (this is a type)
Science (this is a category)
Biology (this is a type)
Chemistry (this is a type)
Anatomy (this is a type)
The difficult part is that sports and science come from the same table (called categories), and soccer, golf, basketball, biology, chemistry and anatomy all come from a different table (called types). In the MySQL table "types" there is a foreign key that points to the id of the entry in the categories table. The current setup in MySQL cannot easily be changed as the navigation of the site is dependent on it.
How could i use php to put the types in between the categories?
Currently the code i have is this:
<?php session_start ();
include 'connect.php';
$result = mysql_query("SELECT * FROM categories JOIN types ON categories.catid = types.typecat");
while($row = mysql_fetch_array($result))
{
echo $row["catname"];
}
?>
However, that outputs "SportsSportsSportsSportsSportsScienceScienceScience," which it obviously shouldnt. There are 5 types in sports, and 3 in science. So i am not sure what is happening there and i cant proceed on to the next step of adding in php to include the types.
I think you need two lists with main category and sub-category, if so you can do as follows
fetch categories from db and display in list 1 with sub category list empty
on change of category submit the form using jquery or javascript
based on category posted fetch sub-categories from database and display in list 2 and select attribute of list 1 make it as selected based on posted category value.
You can use ajax too instead of submitting form.
I believe you have an id_cat in your types table.
Then you should use SQL JOINs.
I don't have the code for you, but the query would be either:
select category, type from categories c, types t on c.id = t.id group by category;
or:
select distinct category from categories;
Then query each category individually.
I suspect the single query would be more efficient.