I have a field in a data feed coming in with some values separated by commas. For one record, the values are:
A06,C05,C06,C15,C18,C19,C21,C22,E05,E22,G11,J02,J07,L04,L07,M01,M05,N03,N07,N10,N11,N12,N18,N19,N20,N24,O02,O03,O04,O06,O09,O14,O15,O16,O20,O21,O31,Q01,Q04,Q08,R07,S08,T08,T12,T23,T32,U01,U03,U04,U06,U13,W09,W11,W16,W19,W30,W45,X02,X03,X12,Z07
I have a separate table with some descriptions as to what each code means. When I query the main table and get this field name as a value, I can use explode to get it into an array and use a foreach loop to output each value.
The problem is, I want to display the description stored in another table. What's the proper way of iterating through this to display these values in a list?
As an example, C21 means "Gated Community."
You can use FIND_IN_SET() function for that.
Example you have record like this
Orders Table
------------------------------------
OrderID | attachedCompanyIDs
------------------------------------
1 1,2,3 -- comma separated values
2 2,4
and
Company Table
--------------------------------------
CompanyID | name
--------------------------------------
1 Company 1
2 Another Company
3 StackOverflow
4 Nothing
Using the function
SELECT name
FROM orders, company
WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)
will result
name
---------------
Company 1
Another Company
StackOverflow
As you have tagged codeigniter you could use the built in Active Record's method $this->db->where_in(); to get the description. For example consider the code below
$codes = array('A06', 'C05', 'C06');
$this->db->where_in('description', $codes);
// Produces: WHERE codes IN ('A06', 'C05', 'C06')
For more information about Active Records of Codeigniter refer Active Record Class
For more information on how mysql WHERE IN works refer Tutorial
Just for follow the books, the best way of doing this in SQL language is to use the relationship.
For understand this I recommend you read this simple paper http://net.tutsplus.com/tutorials/databases/sql-for-beginners-part-3-database-relationships/
and maybe this http://www.informit.com/articles/article.aspx?p=30875&seqNum=5 for SELECT the data, or search for yourself on the web, and I recommend you to try yourself the examples. SQL Relationship Is good and necessary for security and many others reasons.
Related
I'm looking for a way to save data based off a set of rows in another table, but I don't know how to set up the field. Think something similar to using the results of a mysql group_concat as the field. The data is based off the unique combination of rows, rather than one row or field.
What I need to be able to do is:
Store the array itself in the database
Store associated data about the array
Retreive the array
The ability to lookup data about the array using the data in the array
Some options I've thought about:
Saving as an ordered set concatenated into a string.
Saving the serialized array (serialized using php's serialize function).
Saving the set as a hashed string using a reversible hash.
None of these options seem correct so I came here hoping someone has a better answer.
Background:
Supposed I have the following tables:
users {id, other unimportant fields}
products {id, other unimportant fields}
shipments {id, user_id, product_id, date, other unimportant fields}
I want to create a new table called assigned_products where the assigned product is based off of the unique combination of products they've received in the past. So assigned_products should look like:
assigned_products {set_of_products_received (array), product_id (data about the array)}
I don't know of a good way to store set_of_products_received in a database.
Example use:
Suppose I have 100 users who got product A, 100 users who got product B, and 100 users who got products A and B. Suppose then I wanted to give product B to everyone who got product A, product A to everyone who got product B, and product C to everyone who got product A and B. The assigned products table should look like:
+--------------------------+------------+
| set_of_products_received | product_id |
+--------------------------+------------+
| A | B |
| B | A |
| A, B | C |
+--------------------------+------------+
I'm just looking for a better way of storing set_of_products_received
Reading this over I realize it's a bit hard to understand, but I don't really know the appropriate terms to describe this issue (probably why I'm having trouble finding solutions). I'll be happy to clarify if anyone has any questions.
I was wondering if mysql has a way to look at a column and only retrieve the results when it finds a unique column once. For example
if the table looks like this:
id name category
1 test Health
2 carl Health
3 bob Oscar
4 joe Technology
As you can see their are two rows that could have the same category. Is their a way to retrieve the result where the array will one only return the category once?
What I am trying to do is get all the categories in the database so I can loop through them later in the code and use them. For example if I wanted to created a menu, I would want the menu to list all the categories in the menu.
I know I can run
SELECT categories FROM dbname
but this returns duplicate rows where I only need the cateogry to return once. Is there a way to do this on the mysql side?
I assume I can just use php's array_unique();
but I feel like this adds more overhead, is this not something MYSQL can do on the backend?
group by worked perfectly #Fred-ii- please submit this as answer so I can get that approved for you. – DEVPROCB
As requested by the OP:
You can use GROUP BY col_of_choice in order to avoid duplicates be shown in the queried results.
Reference:
https://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html
By using database normalization, you would create another table with an unique id and the category name and by that link those two together, like
select * from mytable1
on mytable1.cat = mytable2.id
group by mytable1.cat
You can ofcourse also use group by without multiple tables, but for the structure, I recommend doing it.
You can use select distinct:
SELECT DISTINCT categories
FROM dbname ;
For various reasons, it is a good idea to have a separate reference table with one row per category. This helps in many ways:
Ensures that the category names are consistent ("Technology" versus "tech" for instance).
Gives a nice list of categories that are available.
Ensures that a category sticks around, even if no names currently reference it.
Allows for additional information about categories, such as the first time it appears, or a longer description.
This is recommended. However, if you still want to leave the category in place as it is, I would recommend an index on dbname(categories). The query should take advantage of the index.
SELECT id, name from dbname GROUP BY categoryname
Hope this will help.
You can even use distinct category.
I am uncertain of the best way to store multiple select options into mysql. Initially, I created a comma separated list of selected values. I have read that this is bad programming practice and also had a difficult time trying to figure out how to search the three columns in my db with the comma separated varchar value (eg: 1,5,17). It seems the best practice would be to create a 3rd table that would insert 3 records for the example above. This table would be linked via an id.
Example:
Table 1 (age levels)has fields id & age level (baby,teenager,adult)
Table 2 has classes id & class name
Table 3 is to store the multiple select options of WHO can attend each class. I guess the fields would be id & classID & ageLevelID
My questions are as follows:
1. how do I efficiently insert this data into table 2 and table 3?
2. how do I pull it all together to search for a person who is looking for a class that allows for just babies and teenagers, for example?
Relating 2 tables is easy, relating 3 tables is a conceptual struggle. Also, am I correct that it is asking for trouble to store comma delimited values in one field? Thank you.
Table agelevel (ageid (unique), agelevel)
Table classes (classid (unique), classname)
Table classesinfo (classid, fieldname,fieldvalue)
With that you could have any 'fieldname' such as agelevel, detailed description, hours, etc and then the value of that field in fieldvalue. This allows your classes to any an infinite number variables attached to a single classid.
So far I had my downloads table denormalized. I had two fields - author and country. They were separated by a space, e.g.: Jack James as for author and us uk for country.
I decided it's time to normalize it so I made a new table called downloads_authors with fields (da_id, downloads_id, da_author, da_country) and now I have:
+-----+------------+---------+----------+
|da_id|downloads_id|da_author|da_country|
+-----+------------+---------+----------+
|1 |1 |Jack |us |
+-----+------------+---------+----------+
|2 |1 |James |uk |
+-----+------------+---------+----------+
So far so good.. but in the way I used to have them, I used explode and with a very bad function, I was getting the desired result - <flag img> Jack, <flag img> James
Now, when I have them in another table I cannot think of a way to do this:
SELECT * FROM downloads and list the respective author(s) without having an inner loop (because if I do a JOIN then I will have the information from downloads again and again).
Desired otuput is:
item
- author
item
- author
- author
Am I wrong about the JOIN and is it the way to go?
Your options are join and use the download information the first time you get a new download id and ignore the download information until you get a new download id. Or do what I said, query the data out and loop to build a new array. Or you could also use group_concat to join the authors together back into a single string.
I would just query out all downloads then query out all authors. Loop over the downloads and assign them to an array where the download id is the key. Then loop over the authors and assign the different authors to a sub-array of the downloads using the download id.
I created a commenting system that allow users to submit comments on each item.
It turned into bit of a project/scope creep and now I need to implement the ability for users to edit their original comments and keep track of those comments.
All comments are located in the comments table
comments: id, comment, item_id, timestamp
Now that revisions must be tracked, I created a new table titled revisions:
comment_id, revision_id, timestamp
All comments (new or old) are entered into the comments table, if the user decides to revise an existing comment, it will be entered as a new record in the comments, then recorded into the revisions table. Once the new comment is entered into the comments table, it will take the id that was created and pass it into the revisions.reivison_id, and it will populate revisions.comment_id with the id of the original comment the user revised (hope I didn't lose you).
Now I've come to the problem I need help with: I need to display a list of all comments for a specific item, which would have a query of something like
select * from comments where item_id = 1
Now that I added the revisions table, I need to retrieve a list of comments for the specific item (just like the above query does) and (and heres the kicker) if any comment is revised, I need to return the most recent version of that comment.
What is the best way of accomplishing this?
I thought about running two queries, one to retrieve all the comments in the comments table, store in an array, and another query to return all records within the revisions table where I would set revisions.comment_id to be distinct and would only want to return the more recent one
the revisions query might look something like this
select comment_id DISTINCT, revision_id, timestamp
from revisions order by timestamp desc
What is the best way of only displaying the most recent version of each comment (some will have revisions and most won't)?
I am not a sql expert, so it might be accomplished using sql or will I need to run two different queries, store data into separate arrays, then run thru each array, compare and strip out the older versions of that comment? example (part in theory) below
foreach($revisions as $r):
$comments = strip key/value from comments array where $r['comment_id'] is
found in comments array
endforeach;
return $comments; // return the comments array after it was stripped of the older comments
I imagine if there was a way of running one query to only return a list of the most recent versions of a comment is the best practice, if so, could you provide the appropriate query for that, otherwise is the two queries into two arrays and striping out values from the comments array the best way or a better way?
Thanks in advance.
First off, I'll add two alternative approaches and then I'll edit with a query to deal with your current schema.
Option 1 - Add a deleted flag to your comments. When a comment is revised, do as you already do but also mak the original as deleted. Then you just need WHERE deleted = 0 wher you want active comments.
Option 2 - Change your revision table to be a clone of the comment table, plus an additional field for when the revision was made. Now, whenever you revise a comment, don't create a new record in comment, just update the existign row and add a new row to the revisions table. This is easily maintained with a trigger and is a very standard auditting pattern.
EDIT Option 3 - A query to cope with your schema.
As described, if I make a comment, then edit it twice (with no other activity), I get something like this...
id | comment | item_id | timestamp
----+--------------+---------+-----------
1 | Hello, | 1 | 13:00
2 | World! | 1 | 14:00
3 | Hello, World | 1 | 15:00
comment_id | revision_id | timestamp
-----------+-------------+-----------
1 | 2 | 14:00
2 | 3 | 15:00
Base on this, the live comment is the only one without an entry in the revision table...
SELECT *
FROM comment
WHERE NOT EXISTS (SELECT * FROM revision WHERE comment_id = comment.id)
AND item_id = #item_id