MySQL query - single product with multiple reviews - mysql

Thank you in advance for any help you may be able to offer!
I'm working with an a bit of an odd database where products are related via tags and are not hierarchical.
I'm trying to select a single product using a SKU number from a table and join it with a table of product reviews like so:
SELECT ims.master_sku, ims.title, ims.price,
ims.description, ir.mvp_number, ir.title,
ir.review, ir.rating, ir.created_on
FROM default_inventory_master_skus AS ims
JOIN default_inventory_reviews AS ir
WHERE ims.master_sku = '22284319'
GROUP BY ir.review;
This gives me around 150 rows - which are all the same product but contain different reviews. My question is how can I return just the one product (as a single row) and somehow convert the reviews into columns associated with that one product?
Again - thank you for your time and help.
Rich

You can do that, although it's not "relational".
Looks like someone wants this data in Excel ;).
With MySQL, you will need to generate an SQL statement and execute it. Either within MySQL (in a procedure) or outside (e.g., in PHP). Query first for the pivot column names, put together the statement, then execute it.
An idea of the implementation is here:
http://www.artfulsoftware.com/infotree/queries.php#78

Related

SQL only get rows that matches full number split by a comma

I'm working on something that shows shops under a specific category, however I have an issue because I store the categories of a shop like this in a record with the id of a category. "1,5,12". Now, the problem is if I want to show shops with category 2, it "mistakens" 12 as category 2. This is the SQL right now.
SELECT * FROM shops WHERE shop_cats LIKE '%".$sqlid."%' LIMIT 8
Is there a way to split the record "shop_cats" by a comma in SQL, so it checks the full number? The only way I can think of is to get all the shops, and do it with PHP, but I don't like that as it will take too many resources.
This is a really, really bad way to store categories, for many reasons:
You are storing numbers as strings.
You cannot declare proper foreign key relationships.
A (normal) column in a table should have only one value.
SQL has poor string functions.
The resulting queries cannot take advantage of indexes.
The proper way to store this information in a database is using a junction table, with one row per shop and per category.
Sometimes, we are stuck with other people's really bad design decisions. If this is your case, then you can use FIND_IN_SET():
WHERE FIND_IN_SET($sqlid, shop_cats) > 0
But you should really fix the data structure.
If you can, the correct solution should be to normalize the table, i.e. have a separate row per category, not with commas.
If you can't, this should do the work:
SELECT * FROM shops WHERE CONCAT(',' , shop_cats , ',') LIKE '%,".$sqlid.",%' LIMIT 8
The table shops does not follow 1NF (1st Normal Form) i.e; every column should exactly one value. To avoid that you need to create another table called pivot table which relates two tables (or entities). But to answer your question, the below SQL query should do the trick.
SELECT * FROM shops WHERE concat(',',shop_cats,',') LIKE '%,".$sqlid.",%' LIMIT 8

How to select number with LIKE?

I have a bunch of products, and a bunch of category pages. One product can be in multiple categories. So in my database I have a products table with a "categories" column. In this column I store the ID's of all the categories that the current product is stored in, its a string seperated with semicolons.
Example: 1;5;23;35;49;.
When I browse to Category Page ID 5, I want to see all products that have 5; in its categories-column. I currently do this by
SELECT * FROM products WHERE categories LIKE "%".category.";%"
The problem is that this matches more than just 5. It matches 15; or 25; aswell.
So questions:
How do I make sure that I only select the number I want? If category is "5" I do not want it to match 15, 25, 35 and so on.
Maybe this is a very bad way of storing the category-ids. Do you have any suggestions of a different way of storing what products that belong to what category?
Others have mentioned that a junction table is the right way to design the database. SQL has a very nice data structure for storing lists. It is not called a "string", it is called a "table".
But, sometimes one is stuck with data in this format and needs to work with it. In that case, the key is to put the delimiters on both side to prevent the problem you are having:
SELECT *
FROM products
WHERE concat(';', categories) LIKE "%;".category.";%"
Your list already ends in a semicolon, so that is not necessary.
Another more typical MySQL solution is find_in_set():
SELECT *
FROM products
WHERE find_in_set(category, replace(categories, ';', ',') > 0;
It is designed for comma-delimited lists. Odd that MySQL supports such a function when storing lists this way is generally a bad idea, but it does. Still, a junction table is better for performance reasons (and for other reasons).
Answers/comments to your two questions:
The only way I can think of that you could do this without modifying your schema (see #2) is to use a MySQL regular expression but this is really not a good idea. See http://dev.mysql.com/doc/refman/5.1/en/regexp.html for documentation though
You are right - this is not a good way to store categories. What you want is a join also known as a junction table (see http://en.wikipedia.org/wiki/Junction_table). One way would be to have three tables: product, category, and a product_categories table. Product and category would have a unique ID as you already have and the product_categories table would have two columns: product_id and category_id. If product 1 belongs to categories 10 and 11, you would have two rows in the product_categories table: 1,10 and 1,11.
I can elaborate if you need more help but this should get you started in re-architecting your database (more) correctly.
You can try changing your like criteria to "%;".category.";%"

SQL Inner joining a column from two tables with a single user id

I've been trying to get this SQL query running for a while now and can't seem to get the last little bit going.
The backend database to all this data is a Drupal install with data spread out across a number of modules, so I need to do a lot of joining to get a certain view table set up that I need for a third-party application.
It's hard to explain the entire schema, but here's the sqlfiddle:
http://sqlfiddle.com/#!2/68df0/2/0
So basically, I have a userid which I map to a profile id through a join. Then I need to use that profile ID to pull the related data about that profile from two other tables. (there should only be one row with each pid in each of the other tables)
So in the end, I would like to see a table with username, othername, and key_id.
I got the first two pieces in there, but just can't seem to figure out how to join in the othername, and keep getting null.
The server is running MySQL.
Thanks guys!
LEFT JOIN other_name
ON profile_link.pid=other_name.pid;

Joining a table stored within a column of the results

I want to try and keep this as one query and not use PHP, but it's proving to be tough.
I have a table called applications, that stores all the applications and some basic information about them.
Then, I have a table with all the types of applications in it, and that table contains a reference to another table which stores more specific data about the specific type of application in question.
select applications.id as appid, applications.category, type.title as type, type.id as tid, type.valuefld, type.tablename
from applications
left join type on applications.typeid=type.id
left join department on type.deptid=department.id
where not isnull(work_cat)
and work_cat != ''
and applications.deleted=0
and datei between '10-04-14' and '11-04-14'
order by type, work_cat
Now, in the old version, there is another query on every single result. Over hundreds of results... that sucks.
This is the query I'd like to integrate so I can get all the data in one result row. (Old is ASP, I'm re-writing it in PHP)
query = "select sum("&adors.fields("valuefld")&") as cost, description from "&adors.fields("tablename")&" where appid = '"&adors.fields("tablename")&"'"
Prepared statements, I'm aware, are the best solution, but for now they are not an option.
You can't do this with a plain SQL query - you need to have a defined set of tables that your query is based on. The fact that your current implementation queries from whatever table is named by tablename from the first result-set means that to get this all in one query, you will have to restructure your data. You have to know what tables you're querying from rather than having it dynamic.
If the reason for these different tables is the different information stored in each requiring different record (column) structures, you might want to look into Key/Value pair storage in a large table. Once you combine the dynamically named ones into a single location you can integrate your two queries together.

Filter a MySQL Result in Delphi

I'm having an issue with a certain requirement to one of my Homework Assignments. I am required to take a list of students and print out all of the students with credit hours of 12 or more. The Credit hours are stored in a separate table, and referenced through a third table
basically, a students table, a classes table with hours, and an enrolled table matching student id to Course id
I used a SUM aggregate grouped by First name from the tables and that all works great, but I don't quite understand how to filter out the people with less than 12 hours, since the SQL doesn't know how many hours each person is taking until it's done with the query.
my string looks like this
'SELECT Students.Fname, SUM(Classes.Crhrs) AS Credits
FROM Students, Classes, Enrolled
WHERE Students.ID = Enrolled.StudentID AND Classes.ID = Enrolled.CourseID
GROUP BY Students.Fname;'
It works fine and shows the grid in the Delphi Project, but I don't know where to go from here to filter the results, since each query run deletes the previous.
Since it's a homework exercise, I'm going to give a very short answer: look up the documentation for HAVING.
Beside getting the desired result directly from SQL as Martijn suggested, Delphi datasets have ways to filter data on the "client side" also. Check the Filter property and the OnFilter record.
Anyway, remember it is usually better to apply the best "filter" on the database side using the proper SQL, and then use client side "filters" only to allow for different views on an already obtained data set, without re-querying the same data, thus saving some database resources and bandwidth (as long as the data on the server didn't change meanwhile...)