Syntax error in complex SQL Query condition - mysql

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".

Related

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.

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

Multiple joins involving same table produces "column doesn't exist" error - MySQL

I'm new to joins and I'm sure this is ridiculously simple. If I remove one join in the query the remainder of the query works regardless of which join I remove. But as shown it gives the error saying the column doesn't exist. Any pointers?
select
loc_carr.address1 as carr_addr1,
loc_cust.address1 as cust_addr1
from db_name.carrier, db_name.customer
join db_name.location as loc_carr on vats.carrier.location_id=loc_carr.location_id
join db_name.location as loc_cust on vats.customer.location_id=loc_cust.location_id
thanks
I'll take a guess that there is a column named something like carrier_id that can be used to join the carrier and customer tables. Given that assumption, try this:
select
loc_carr.address1 as carr_addr1
, loc_cust.address1 as cust_addr1
from vats.carrier as a
join vats.customer as b
on b.carrier_id=a.carrier_id
join vats.location as loc_carr
on loc_carr.location_id=a.location_id
join vats.location as loc_cust
on loc_cust.location_id=b.location_id
Notice the use of aliases for the table references to make things easier to read. Also note how I'm using explicit SQL join syntax (instead of listing tables separated by commas).
#Bob Duell has the solution for your problem. To understand better why this error is produced, notice that in the FROM clause, you "join" tables using both explicit JOIN syntax and the implicit joins with comma: , which is (almost) equivalent to a CROSS JOIN. The precedence however of JOIN is stronger than the comma , operator. So, that part is parsed like this:
FROM
( db_name.carrier )
,
( ( db_name.customer
JOIN db_name.location AS loc_carr
ON carrier.location_id = loc_carr.location_id -- this line
) -- gives the error
JOIN join db_name.location AS loc_cust
ON customer.location_id = loc_cust.location_id
)
In the mentioned line above, the vats.carrier.location_id throws the error, as there is no carrier table in that scope (inside that parenthesis).

What's wrong with this mySQL query?

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.

mysql query not working

i am working on a query which joins several tables.here's the code.
the query works fine until the time i add the third line SUM(SaleItems_T.qtymajor) AS sales. i get an error message which says
Unknown column 'SaleItems_T.qtymajor' in 'field list'
I am trying to build an reorder worksheet.Help is much appreciated.
SELECT ProductMaster_T.ProductName_VC AS PGroup,
StockMain_T.ItemDescription AS Item,
SUM(SaleItems_T.qtymajor) AS sales,
stockbuffers_T.buffer_qty AS BufferQty,
(stkbalance_T.AJ1+stkbalance_T.AR2+stkbalance_T.AD3+stkbalance_T.DX4) AS Stock,
(stkbalance_T.AJ1+stkbalance_T.AR2+stkbalance_T.AD3+stkbalance_T.DX4)-stockbuffers_T.buffer_qty AS Result
FROM ProductMaster_T, StockMain_T, stockbuffers_T, stkbalance_T
WHERE StockMain_T.ItemCode = stockbuffers_T.itemcode
AND
StockMain_T.ItemCode = stkbalance_T.itemid
AND
ProductMaster_T.ProductID = StockMain_T.ProdID
AND
SaleItems_T.ItemID = StockMain_T.ItemCode
ORDER BY
ProductName_VC,ItemDescription ASC
You haven't referenced the SaleItems_T table in your query, either in the FROM clause, or through a JOIN.
This is where your query is wrong:
FROM ProductMaster_T, StockMain_T, stockbuffers_T, stkbalance_T
Change that to:
FROM ProductMaster_T, StockMain_T, stockbuffers_T, stkbalance_T, SaleItems_T
(Please no vote for this. I only put it here as comment space is not suitable fot such long comment.)
You should really use explicit JOIN ... ON join_condition syntax instead of the implicit JOIN via WHERE conditions (this is really old way to do it). It's better because it's hard to forget a condition (or a table, as you did!) and thus less error-prone. It also separates the join conditions (which you'll use in almost every query) from the other conditions you may have in various queries.
So, instead of
FROM ProductMaster_T, StockMain_T
WHERE ProductMaster_T.ProductID = StockMain_T.ProdID
write:
FROM ProductMaster_T
JOIN StockMain_T
ON ProductMaster_T.ProductID = StockMain_T.ProdID
It's also nice to use aliases (with the (optional) AS keyword). It make code more readable:
FROM ProductMaster_T AS p
JOIN StockMain_T AS m
ON p.ProductID = m.ProdID
The whole query could be written as:
SELECT
master.ProductName_VC AS PGroup,
main.ItemDescription AS Item,
SUM(items.qtymajor) AS sales,
buf.buffer_qty AS BufferQty,
(bal.AJ1 + bal.AR2 + bal.AD3 + bal.DX4)
AS Stock,
(bal.AJ1 + bal.AR2 + bal.AD3 + bal.DX4) - buf.buffer_qty
AS Result
FROM ProductMaster_T AS master
JOIN StockMain_T AS main
ON master.ProductID = main.ProdID
JOIN stockbuffers_T AS buf
ON main.ItemCode = buf.itemcode
JOIN stkbalance_T AS bal
ON main.ItemCode = bal.itemid
JOIN SaleItems_T AS items
ON items.ItemID = main.ItemCode
ORDER BY
ProductName_VC ASC,
ItemDescription ASC
GROUP BY ??? main.ItemCode ??? --- depends on your tables'
--- relationships