Related Products SQL Query - php

I am trying to show something similar to related products on on my website. I have tested the following query, and I get no errors; but I get no results either.
<?php
$relatedStmt = $db->query("SELECT * FROM items WHERE tag LIKE id = 1 LIMIT 3");
?>
I also tried %1% and it displayed ALL the results, I assumed the code was thinking the query was just SELECT * FROM items.
The tags in the column are displayed in the following format: tagone two three four, so I am trying to display the products that have similar tags, hence why I used the LIKE clause.
Table screenshot
The current query is to relate with this query: SELECT * FROM items WHERE id = 1. So LIKE id = 1 is to find the tags that match this query to show the related products.

LIKE doesn't work the way you seem to expect. It's a character for character comparison, with wildcards, between the operands.
Of the mysql functions, closest to what you want is probably LOCATE or FIND_IN_SET. There are split solutions in other questions, e.g. "Can Mysql Split a column?" and "Split a MYSQL string from GROUP_CONCAT into an ( array, like, expression, list) that IN () can understand". However, even so there is no good way to compare the individual tags in your concatenated tag column with the individual tags of the other rows in your table.
Therefore, I think you'd be better off moving the tags into their own table with item_id as a foreign key. Then the solution is trivial (SQLFiddle):
-- Related Items
SELECT *
FROM items
WHERE id in (SELECT DISTINCT item_id
FROM tags t
JOIN (SELECT tag
FROM tags
WHERE item_id = 1
) t1 ON t1.tag = t.tag
WHERE item_id != 1
)
;

i am unsure about that id = 1 thing in your query but anyway you could try this: SELECT * FROM items WHERE tag LIKE '%search_this_tag%' LIMIT 3

Related

Get an array of all columns starting with the same characters.

This is quite difficult to explain in the title, so I'll do my best here. Basically I have a column in a MySQL products table that contains rows like:
FEL10
FEL20
FEL30
PRO05
PRO07
PRO08
VAI12
VAI13
VAI14
These are the categories ("FEL","PRO","VAI") and a identification number of my products ("10", "20" and so on). I need an SQL select query that creates me a textual array like:
FEL*
PRO*
VAI*
With this array I need to create a listbox, that allows me to choose a category (regardless of the identification number). Once I choose a category, let's say PRO*, I will need to do the reverse action: print all the products info related to PRO05, PRO07 and PRO08.
How do you think you can achieve this? I have been trying using the DISTINCT statement but I need to filter only the first characters, otherwise it will be useless. I also tried the SUBSTRING() and LEFT() functions, but they seem not to be working (I get an SQL Syntax error).
--
Thanks for your help as always
What is wrong with?
SELECT distinct left(col, 3) as category FROM `table1`
MySQL LIKE to the resque:
SELECT col1 FROM table1 WHERE col1 LIKE 'FEL%';
This way you have to add all cases using OR.
Alternative - REGEXP:
SELECT col1 FROM table1 WHERE col1 REGEXP '(FEL|PRO|VAI).*'
Then it's just a matter of writing proper regex.
I would use extra col to group your items - to avoid such selecting altogether (which should be quite expensive on bigger dataset).
https://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp
To get the list of the 3-letter codes use:
select distinct left(combicode, 3)
from mytable;
When a user selects one of the values use this to get all matching entries:
select *
from mytable
where combicode like concat(#category, '%');
(Aside from that: It's a bad idea to have concatenated values in one column. Why not have one column for the category and another for the product code? Then there would be no problem at all.)

Most efficient way to get the data from database

So what i have is pretty simple.
I have 1 table
CategorieMain
like
CatMainid
CatMainName
and 1 table:
CategorieSub
like
CatId
CatName
CatMainId
'
What i want is :
A list with all the CatMainName's and under the names all the CatSubNames.
CatMainId1
all CatSubNames with CatMainId1
CatMainId2
all CatSubNames with CatMainId2
Etc Etc
Currently i use php to get the data like
SELECT * from Categoriemain
and in the while loop i do
SELECT * FROM CategorieSub WHERE CatMain id = $row['CatMainId']
But this is very inefficient because now if i have 10 CatMainId's i do 10 query's (for each one a while)
What is the most efficient way to get a list like this, i was thinking about putting it in arrays or something but i couldn't get it working?
SELECT * FROM Categoriemain
JOIN CategorieSub ON Categoriemain.CatMainid=CategorieSub.Catmainid
ORDER BY Categoriemain.CatMainid
Use one query:
SELECT Categoriemain.*, CategorieSub.CatSubNames FROM Categoriemain
JOIN CategorieSub ON Categoriemain.CatMainid=CategorieSub.Catmainid
Edited, removed GROUP BY
With this query, you don't need the while loop.
I have also added the CatSubNames to the output list of the query fields.

MySQL - selecting from multiple tables, possibly without joins?

It's been a while since I needed help, but today I'm here to basically get assistance from your knowledge. I'm currently quite stuck on a very annoying SQL problem, which is the following.
I have two tables. Painteditems, and specialitems. Both tables have unique column names (painteditemid, specialitemid etc), yet both tables share similar values. I want to get results from both tables.
Let's say this is my setup:
PaintedItems
paintedItemName
paintedItemColor
visible
SpecialItems
specialItemName
specialItemColor
visible
I used this query:
SELECT *
FROM `painteditems` AS pa,
`specialitems` AS sp
WHERE (pa.`visible` = 1
OR sp.`visible` = 1)
AND (pa.`painteditemname` = 'itemname1'
OR sp.`specialitemname` = 'itemname1')
AND (pa.`painteditemcolor` = 'black'
OR sp.`specialitemcolor` = 'black')
That resulted in:
Showing rows 0 - 29 ( 259,040 total, Query took 39.4352 sec)
even though both tables contain only 10.000 rows altogether. Adding this did nothing:
GROUP BY pa.`painteditemid`, sp.`specialitemid`
Still 260k rows. How should I approach this?
Thank you in advance.
edit: fixed spacing, code blocks
Sure sounds like you want a UNION between the two tables. Right now, you are getting a cartesian product which is why the results are so large:
select *, 'painted' Source
from painteditems
where visible = 1
and painteditemname = 'itemname1'
and painteditemcolor = 'black'
union all
select *, 'special' Source
from specialitems
where visible = 1
and specialitemname = 'itemname1'
and specialitemcolor = 'black'
You will need to replace the SELECT * with your column names. Also the number of columns and datatypes must match in both queries.
UNION ALL will return all rows from both tables, if you only want DISTINCT rows then you will want to use UNION
The UNION operator is used to combine the result-set of two or more SELECT statements. Defiantly You can make use of UNION as shown in the #bluefeet's answer If you meet below conditions.
SELECT statement within the UNION must have the same number of
columns
The columns must also have similar data type
The columns in each SELECT statement must be in the same order.
I would do this with a union all in the subquery:
select *
from ((select paintedItemName as ItemName, paintedItemColor as ItemColor, visible, 'Painted' as which
from painteditems
) union all
(select specialItemName, SpecialItemColor, visible, 'Special' as which
from specialitems
)
) t
where visible = 1 and itemname = 'itemname1' and itemcolor = 'black'
This allows you to have only one set of results. In a union, the column names come from the first subquery, which this renames to more generic names. The reason I prefer this approach is because the where clause does not need to be repeated multiple times -- which can lead to errors and maintenance problems.

Why is sql MAX function not working properly?

I have this query working to some extent.
It returns the correct value for 'rating' (which output as 7, the highest rating), but the output for 'content' is from a different row in the table. (not the row of the highest rating, which is 7)
$bestAnswerQuery = MYSQL_QUERY("SELECT content, MAX(rating) as rating FROM answers WHERE questionID = '$questionID'");
$fetchBestAnswer = MYSQL_FETCH_ASSOC($bestAnswerQuery);
echo "$fetchBestAnswer[content] $fetchBestAnswer[rating]";
Can anyone tell me why? I've searched and cannot find out why this isn't working properly.
This is not how aggregates like MAX work in SQL. Your confusion is coming from MySQL's (default) non-ANSI handling of aggregates.
Aggregates like MAX operate over groups. In the absence of a group by clause, the entire result set is considered to be a single group. Only expressions that are part of a group by clause can be included in a select clause without being enclosed in an aggregate. In the case where there is no group by, then all columns or expressions in the select clause must be contained in an aggregate.
However, MySQL's default configuration breaks this by allowing you to include non-grouped expressions in the select clause, but the row that any given expression uses to obtain its value is undefined; it could be any row within the group.
After that long-winded answer, if what you want to get is the maximum rating and the associated content column from the table for a given question, you can just do this:
select
rating,
content
from answers
where questionID = '$questionID'
order by rating desc
limit 1;
Change the query a little like this:
$bestAnswerQuery = mysql_query("SELECT content, rating as rating
FROM answers
WHERE questionID = '$questionID'
AND rating = MAX(rating)");

How to combine these three sql queries into one?

How to combine these two sql queries into one?
SELECT DISTINCT * FROM rss WHERE MATCH(content,title) AGAINST ('$filter')
SELECT COUNT(content) FROM rss WHERE MATCH(content,title) AGAINST ('$filters')
And if the result is 0 from the above query
-
SELECT DISTINCT * FROM rss WHERE content LIKE '%$filters%' OR title LIKE '%$filters%';
$filter .= $row['filter'];
$filters = $row['filter'];
$filters may be more than one keyword
You do not have to use query 2,
mysql_num_rows will indicate how many rows for query 1, so just discard query 2
if mysql_num_rows return zero, then proceed with query 3
To combine three queries into one, use OR
SELECT DISTINCT * FROM rss
WHERE
(MATCH(content,title) AGAINST ('$filter'))
OR
(content LIKE '%$filter%' OR title LIKE '%$filter%')
As explained above, you do not really need to do count first.
If $filter contains lots of keyword, then just repeating like
(content LIKE '%$filter_1%' OR title LIKE '%$filter_1%') OR
(content LIKE '%$filter_2%' OR title LIKE '%$filter_2%') OR ...
You can combine 1 and 3 using UNION ALL. But you can't merge 2nd with other 2, because COUNT returns aggregate for a bunch of rows.
You are better off writing a stored procedure in your case, than trying to stuff in all three into a single statement.
EDIT (via sv88erik): Since you are using UNION ALL, you don't need a DISTINCT keyword in each query.

Categories