What's wrong with this mySQL query? - mysql

Consider following two tables:
tag_names (tag_id, tag_name)
tag_links (tag_id, image_id)
An image can have multiple tags, I want to select all tags for a specific image id.
I am trying following query, but it doesnt seem to select correctly (selects only one row), What is wrong with it?
SELECT tag_name
FROM tag_names
LEFT JOIN tag_links.tag_id = tag_names.tag_id
WHERE tag_links.image_id = $image_id
Edit: I'm using CodeIgniter Active record query, but I wrote in basic SQL format so that if someone is not fimiliar with CodeIgniter can help. However, this query works fine with simple mysql format (without using CodeIgniter) but strangely does not work with CodeIgniter, even there is no any problem with the syntax, it just selects one row.
Here is CodeIgniter Syntax:
$this->db->select('tag_name');
$this->db->from('tag_names');
$this->db->join('tag_links', 'tag_links.tag_id = tag_names.tag_id', 'left');
$this -> db -> where('tag_links.image_id', (int)$image_id);
$query = $this->db->get();

Try this:
SELECT tag_name
FROM tag_names
LEFT JOIN tag_links
ON tag_links.tag_id = tag_names.tag_id
WHERE tag_links.image_id = $image_id
IMHO you forgot to join table (properly with ON statement) you are using.
EDIT: I have 2 ideas how to get rid of the problem:
First:
Change the line with SELECT
$this->db->select('tag_names.tag_name');
Second:
Use select() function with complete query:
$this->db->select($query, false);
$this->db->select() accepts an optional second parameter. If you set
it to FALSE, CodeIgniter will not try to protect your field or table
names with backticks. This is useful if you need a compound select
statement.
from: http://codeigniter.com/user_guide/database/active_record.html#select

It seems that you have a syntax error (you forgot tag_links in JOIN clause). By the way in my opinion you don't need LEFT JOIN for this purpose otherwise you may get incorrect results.
SELECT tag_name
FROM
tag_names
JOIN tag_links ON tag_links.tag_id = tag_names.tag_id
WHERE tag_links.image_id = $image_id

SELECT tag_names.tag_name
FROM tag_links
LEFT JOIN tag_names.tag_id = tag_links.tag_id
WHERE tag_links.image_id = $image_id
tag_names is only going to have single entry for a given ID, which means your query will return a single result. You need to primarily select from tag_links and then join the name of the tag on top of it, so you correctly select from the table with the multiple entries.

Related

How to create mysql function

i have the following sql query
SELECT id,
title,
total_likes,
IFNULL(SELECT 1 FROM 'likedata' WHERE user_id=$UID AND post_id=posts.id)0) AS is_liked
FROM 'posts'
I want to create mysql function to make my query bit shorter,
i don't know how to wrap the second query into sql function and pass 2 variables ($UID and $PID) to function to make this query shorter and more understandable.
any help would be great, thanks in advance
This isn't a good use case for a function.
A more fluent way of expressing this in SQL would be to use a left outer join, e.g:
SELECT posts.id, posts.title, posts.total_likes,
(likedata.id IS NOT NULL) AS is_liked
FROM posts
LEFT JOIN likedata ON (
posts.id = likedata.post_id AND likedata.user_id = $UID
)
You can see this in action here.
You can actually simply use exists. MySQL treats booleans as numbers, so:
SELECT p.id, p.title, p.total_likes,
( EXISTS (SELECT 1 FROM likedata ld WHERE ld.post_id = p.id AND ld.user_id = $UID)
) as is_liked
FROM posts p;
This seems closest to your original intent.
#duskwuff's answer is also a typical way to approach this. There is a slight different, because duplicates in likedata would result in duplicate rows in the result set using a join.
For either form, you want an index on likedata(post_id, user_id). And if you are passing $UID in, you should be using parameterized queries.

MAX(Date) is giving empty result

I have a table with exchange rate like below
And I am using the maxofdate to pick all these values based on currency code. But the query is giving blank.
Select USDAMOUNT * dbo.EXCHANGERATEAMT
from dbo.Amount_monthly
Left Join dbo.EXCHANGERATE on dbo.Amount_monthly.Currencycode=dbo.EXCHANGERATE.fromcurrencycode
WHERE ValidToDateTime = (Select MAX(ValidToDateTime) from dbo.EXCHANGERATE)
AND dbo.EXCHANGERATE.EXCHANGERATETYPECODE = 'DAY'
Using this statement
CONVERT(DATE,ValidToDateTime) = CONVERT(DATE,GETDATE()-1)
instead of subquery is giving me expected result.
Can someone correct this.
thanks in advance.
If I understand correctly, you need two things. First, the condition for the max() needs to match the condition in the outer query. Second, if you really want a left join, then conditions on the second table need to go in the on clause.
The resulting query looks like:
Select . . .
from dbo.Amount_monthly am Left Join
dbo.EXCHANGERATE er
on am.Currencycode = er.fromcurrencycode and
er.ValidToDateTime = (Select max(er2.ValidToDateTime)
from dbo.EXCHANGERATE er2
where er2.EXCHANGERATETYPECODE = 'DAY'
) and
er.EXCHANGERATETYPECODE = 'DAY';
I would write this using window functions, but that is a separate issue.
Try removing WHERE clause for ValidToDateTime and include it in the JOIN as AND condition
SELECT USDAMOUNT * dbo.EXCHANGERATEAMT
FROM dbo.Amount_monthly
LEFT JOIN dbo.EXCHANGERATE
ON dbo.Amount_monthly.Currencycode = dbo.EXCHANGERATE.fromcurrencycode
AND ValidToDateTime = (SELECT MAX(ValidToDateTime) --remove WHERE clause
FROM dbo.EXCHANGERATE)
AND dbo.EXCHANGERATE.EXCHANGERATETYPECODE = 'DAY';
I cleaned up your query a bit: as the other folks mentioned you needed to close the parentheses around the MAX(Date) sub-query, and if you reference a LEFT JOINed table in the WHERE clause, it behaves like an INNER JOIN, so I changed to in INNER. You also had "dbo" sprinkled in as a field prefix, but that (the namespace) only prefixes a database, not a field. I added the IS NOT NULL check just to avoid SQL giving the "null values were eliminated" SQL warning. I used the aliases "am" for the first table and "er" for the 2nd, which makes it more readable:
SELECT am.USDAMOUNT * er.EXCHANGERATEAMT
FROM dbo.Amount_monthly am
JOIN dbo.EXCHANGERATE er
ON am.Currencycode = er.fromcurrencycode
WHERE er.ValidToDateTime = (SELECT MAX(ValidToDateTime) FROM dbo.EXCHANGERATE WHERE ValidToDateTime IS NOT NULL)
AND er.EXCHANGERATETYPECODE = 'DAY'
If you're paranoid like I am, you might also want to make sure the exchange rate is not zero to avoid a divide-by-zero error.

ID lost after left join on table

Hey I tried this thread but it doesn't work and i can't figure out why...
here's my SQL:
SELECT * FROM gone_items
LEFT JOIN items
ON gone_items.item_ID=items.ID
WHERE
gone_items.aus_ID='$ID'
ORDER BY items.name ASC
Now, I fetch that via PHP and have a $row and try another mysql to get the individual ID's of the gone_items table. But if i use $row['ID'] I get the ID of the items.ID not the one from gone_items.ID.
I tried setting the variable manually in the first query but it doesn't work.
I also tried this: MYSQL Left join A.table and b.table while retaining a.table id
Also didn't help me...
All I want is to retain the ID (Primary key) from the gone_items table..
Can anyone please tell me what I'm doing wrong ?
Love
Gram
EDIT
//Query for Joined infos
$sqlx="SELECT foto_res_ausgeliehene_geg.ID, foto_res_ausgeliehene_geg.aus_ID, foto_res_ausgeliehene_geg.geg_ID, foto_res_ausgeliehene_geg.zusaetzliches, foto_res_gegenstaende.ID, foto_res_gegenstaende.bezeichnung, foto_res_gegenstaende.seriennummer, foto_res_gegenstaende.interne_seriennummer, foto_res_gegenstaende.zusaetzliches FROM foto_res_ausgeliehene_geg
LEFT JOIN foto_res_gegenstaende
ON foto_res_ausgeliehene_geg.geg_ID=foto_res_gegenstaende.ID
WHERE
foto_res_ausgeliehene_geg.aus_ID='$ID'
ORDER BY foto_res_gegenstaende.bezeichnung ASC
";
$ergebnisx = mysqli_query($db,$sqlx);
while ($zeilex = mysqli_fetch_assoc($ergebnisx))
{
//Query for individual infos
$sqly="SELECT * FROM foto_res_ausgeliehene_geg
WHERE `geg_ID`='".$zeilex['ID']."'
AND `aus_ID`='$ID'
GROUP BY `geg_ID`
";
$ergebnisy = mysqli_query($db,$sqly);
while ($zeiley = mysqli_fetch_assoc($ergebnisy))
{};
Now I did select all items individually. The foto_res_ausgeliehene_geg.ID still merges with the foto_res_gegenstanede.ID due to the LEFT JOIN.
So if i access $zeilex['ID'] im getting the ID of foto_res_gegenstaende.ID.
Would it help if I rename the ID field in one of the tables into lets say item_ID ?
Thanks alot.
Love
Gram.
Instead of using select *, you should explicitly state what items you want to select. Else you can get conflicts with multiple id fields. In your case something like:
select gone_items.id, gone_items.column1, gone_items.column2, items.column1, items.column2
It is also considered good practice, to limit the amount of data there is being selected. But is meanwhile also a highly debateable what is the right way. Performance issue in using SELECT *?
WORKS!
I simply renamed one of the Primary ID keys to something else, in this case, one of them got ID -> item_ID. The other one still is ID that way the left join won't merge them.
yolo
EDIT
WORKING CODE
$sqlx="SELECT foto_res_ausgeliehene_geg.item_ID, foto_res_ausgeliehene_geg.aus_ID, foto_res_ausgeliehene_geg.geg_ID, foto_res_ausgeliehene_geg.zusaetzliches, foto_res_gegenstaende.ID, foto_res_gegenstaende.bezeichnung, foto_res_gegenstaende.seriennummer, foto_res_gegenstaende.interne_seriennummer, foto_res_gegenstaende.zusaetzliches FROM foto_res_ausgeliehene_geg
LEFT JOIN foto_res_gegenstaende
ON foto_res_ausgeliehene_geg.geg_ID=foto_res_gegenstaende.ID
WHERE
foto_res_ausgeliehene_geg.aus_ID='$ID'
ORDER BY foto_res_gegenstaende.bezeichnung ASC
";
$ergebnisx = mysqli_query($db,$sqlx);
while ($zeilex = mysqli_fetch_assoc($ergebnisx))
{
//Query for individual infos
$sqly="SELECT * FROM foto_res_ausgeliehene_geg
WHERE `item_ID`='".$zeilex['item_ID']."'
";
$ergebnisy = mysqli_query($db,$sqly);
while ($zeiley = mysqli_fetch_assoc($ergebnisy))
{

Syntax error in complex SQL Query condition

I am having some trouble with my sql statement.
Here is a picture of the relevant tables:
A product can be in multiple categories.
A single product can have multiple varietycategories (ie: size, color, etc)
a varietycategory can have multiple varietycategoryoptions (ie: small, medium, large)
the table searchcriteria.criterianame loosly relates to varietycategory.category
the table searchcriteriaoption.criteriaoption loosely relates to varietycategoryoption.descriptor.
I get the searchcriteria.criterianame and use that string as the value we want to match with varietycategory.category and we also have to get the various searchcriteriaoption.criteriaoption strings (for that searchcriteria.criterianame) and match that against varietycategoryoption.descriptor for that varietycategory.category.
Here is the sql:
SELECT DISTINCT categories.*, product.*
FROM (categories, product, product_category)
LEFT JOIN varietycategory ON varietycategory.productid = product.id
LEFT JOIN varietycategoryoption ON varietycategoryoption.varietycategoryid = varietycategory.id
WHERE product_category.categoryid=4
AND product.id=product_category.productid
AND categories.category_id=product_category.categoryid
AND (
(varietycategory.category = 'color' AND (varietycategoryoption.descriptor='red' OR varietycategoryoption.descriptor='blue'))
OR
(varietycategory.category = 'size' AND (varietycategoryoption.descriptor = 'small' OR varietycategoryoption.descriptor='medium'))
)
but I get an error:
Unknown column 'varietycategory.id' in 'on clause'
I have tried to figure out what I am doing wrong. I tried simplifying the query a bit (just to try and determine what part of the sql query was causing the problem) to only match the searchcriteria.category string with the varietycategory.category and the query returns the data set correctly.
Here is the working query (this query is simplified and insufficient):
SELECT DISTINCT categories.*, product.*
FROM (categories, product, product_category)
LEFT JOIN varietycategory ON varietycategory.productid = product.id
WHERE product_category.categoryid=4
AND product.id=product_category.productid
AND categories.category_id=product_category.categoryid
AND (varietycategory.category = 'color' OR varietycategory.category = 'size' OR varietycategory.category='shape');
But I also need to be able to match against the varietycategoryoptions as well.
Just to avoid confusion, I am only using searchcriteria to get the field category and use it as a string to match against the varietycategory.category
and I am only using searchcriteriaoption to get the field criteriaoption and use it as a string to match against varietycategoryoption.descriptor
Does anyone know what I am doing wrong with my 1st query?
Please do help as SQL is not expertise.
Thank you!
The error is at:
OR
(varietycategory.category = 'size' (varietycategoryoption.desciptor = 'small' OR varietycategoryoption.descriptor='medium'))
^
|
An operator (AND, OR) is missing here
This has nothing to do with the join syntax, by the way.
Do not mix implicit and explicit joins. Your query should look like:
SELECT DISTINCT c.*, p.*
FROM product_category pc join
categories c
on c.category_id = pc.categoryid join
product p
on p.id = pc.productid join
varietycategory vc
ON vc.productid = p.id
WHERE c.categoryid = 4 AND
vc.category in ('color', 'size', 'shape');
You probably don't need the distinct, but that depends on the data. The left join is unnecessary because you are filtering on the second table in the where.
A simple rule: Never use commas in the from clause. To help, MySQL has scoping rules that can cause queries to break when you mix implicit and explicit join syntax.
The problem was a misspelled field on the table varietycategory, which I named
vcid, when I almost always name my table primary key id's "id".

MySQL: Subquery returns more than 1 row

I know this has been asked plenty times before, but I cant find an answer that is close to mine.
I have the following query:
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, o.organisation_name
FROM db_cases c, db_custinfo ci, db_organisation o
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2'
AND organisation_name = (
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
)
AND s.sites_site_ID = c.sites_site_ID)
What I am trying to do is is get the cases, where the sites_site_ID which is defined in the cases, also appears in the db_sites sites table alongside its organisation_ID which I want to filter by as defined by "organisation_ID = '111'" but I am getting the response from MySQL as stated in the question.
I hope this makes sense, and I would appreciate any help on this one.
Thanks.
As the error states your subquery returns more then one row which it cannot do in this situation. If this is not expect results you really should investigate why this occurs. But if you know this will happen and want only the first result use LIMIT 1 to limit the results to one row.
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
LIMIT 1
Well the problem is, obviously, that your subquery returns more than one row which is invalid when using it as a scalar subquery such as with the = operator in the WHERE clause.
Instead you could do an inner join on the subquery which would filter your results to only rows that matched the ON clause. This will get you all rows that match, even if there is more than one returned in the subquery.
UPDATE:
You're likely getting more than one row from your subquery because you're doing a cross join on the db_sites and db_cases table. You're using the old-style join syntax and then not qualifying any predicate to join the tables on in the WHERE clause. Using this old style of joining tables is not recommended for this very reason. It would be better if you explicitly stated what kind of join it was and how the tables should be joined.
Good pages on joins:
http://dev.mysql.com/doc/refman/5.0/en/join.html (for the right syntax)
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html (for the differences between the types of joins)
I was battling this for an hour, and overcomplicated it completely. Sometimes a quick break and writing it out on an online forum can solve it for you ;)
Here is the query as it should be.
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, c.sites_site_ID
FROM db_cases c, db_custinfo ci, db_sites s
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2' AND (s.organisation_ID = '111' AND s.sites_site_ID = c.sites_site_ID)
Let me re-write what you have post:
SELECT
c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName,
c.cases_timestamp, c.sites_site_ID
FROM
db_cases c
JOIN
db_custinfo ci ON c.userInfo_ID = ci.userinfo_ID and c.cases_status = '2'
JOIN
db_sites s ON s.sites_site_ID = c.sites_site_ID and s.organization_ID = 111