MySQL JOIN 3 tables in one query - mysql

Could you please help me to make this query works
SELECT *
FROM `SC_orders`
LEFT JOIN `SC_customer_reg_fields_values` using(customerID)
WHERE (`statusID` = 2 OR `statusID` = 3 OR `statusID` = 21 OR `statusID` = 25 OR `statusID` = 26) AND DATE(order_time) > '2012-12-01 00-00-00'
LEFT JOIN `SC_ordered_carts`
ON orderID = orderID
GROUP BY orderID
I try to combine information from 3 tables in one output. This query works fine without last LEFT JOIN and Grouping. Where is my mistake?

The where needs to be after the last join. also, the second ON clause is ambiguous and I think the group by is unnecessary since you don't have any aggregate functions:
SELECT *
FROM `SC_orders`
LEFT JOIN `SC_customer_reg_fields_values` using(customerID)
LEFT JOIN `SC_ordered_carts` using(orderID)
WHERE (`statusID` = 2 OR `statusID` = 3 OR `statusID` = 21 OR `statusID` = 25 OR `statusID` = 26) AND DATE(order_time) > '2012-12-01 00-00-00'

Related

How group values in Mysql query?

I have query:
SELECT p.`obj_id` ,
p.`alt_name` ,
o.`name`,
p.`id`,
oc.`text_val`,
oc.`float_val`
FROM `cms3_hierarchy` p
LEFT JOIN `cms3_objects` o
ON p.`obj_id` = o.`id`
LEFT JOIN `cms3_object_content` oc
ON p.`obj_id` = oc.`obj_id`
WHERE (oc.`field_id` = 221 OR oc.`field_id` = 248 )
AND (p.`rel`=903687) LIMIT 0,50
But answer like this:
obj_id name id 221 248
1 first 2 null
1 first null 3
Well, i have one obj_id with different values.
But for me this is look like this:
obj_id name id 221 248
1 first 2 3
How to do this?
Conditions on the right table of a LEFT JOIN should be specified only inside the ON clause, when they are in the WHERE clause, the join automatically turns into an INNER JOIN because of NULL comparison.
Also, use IN() to compare the same column to multiple values instead of OR . I also used MAX() to group the rows into one row, so :
SELECT p.obj_id , p.alt_name , o.name,p.id,
MAX(CASE WHEN oc.field_id = 221 THEN oc.text_val END) as col_221,
MAX(CASE WHEN oc.field_id = 1123 THEN oc.text_val END) as col_1123,
MAX(oc.float_val)
FROM cms3_hierarchy p
LEFT JOIN cms3_objects o
ON p.obj_id = o.id
LEFT JOIN cms3_object_content oc
ON p.obj_id = oc.obj_id and oc.field_id in(221,248,1123)
WHERE p.rel=903687
LIMIT 0,50
GROUP BY p.obj_id , p.alt_name , o.name,p.id

using joins together with aggregates, and retrieving rows when no aggregate exists

The following query on my MySQL tables returns rows from the purchaseorder table that have corresponding entries in the deliveryorder table. How do I construct this query so that I get rows from the purchaseorder table even if no corresponding rows exist in the deliveryorder table? If the users want to see sql table CREATE statements, I can post those, but I'm not posting now as it really makes the question too big.
SELECT
`purchaseorder`.`id` AS `po_id`,
`purchaseorder`.`order_quantity` AS `po_order_quantity`,
`purchaseorder`.`applicable_approved_unit_rate` AS `po_unit_rate`,
`purchaseorder`.`applicable_sales_tax_rate` AS `po_tax_rate`,
`purchaseorder`.`order_date` AS `po_order_date`,
`purchaseorder`.`remarks` AS `po_remarks`,
`purchaseorder`.`is_open` AS `po_is_open`,
`purchaseorder`.`is_active` AS `po_is_active`,
`purchaseorder`.`approved_rate_id` AS `po_app_rate_id`,
`supplier`.`name` AS `sup_name`,
SUM(`deliveryorder`.`quantity`) AS `total_ordered`
FROM `purchaseorder`
LEFT JOIN `deliveryorder` ON (`deliveryorder`.`purchase_order_id` = `purchaseorder`.`id`)
INNER JOIN `approvedrate` ON (`purchaseorder`.`approved_rate_id` = `approvedrate`.`id`)
INNER JOIN `supplier` ON (`approvedrate`.`supplier_id` = `supplier`.`id`)
WHERE (
`purchaseorder`.`is_active` = 1
AND `purchaseorder`.`is_open` = 1
AND `deliveryorder`.`is_active` = 1
AND `approvedrate`.`material_id` = 2
)
HAVING `purchaseorder`.`order_quantity` >= `total_ordered` + 1
You have an aggregating function but no GROUP BY clause, which is wierd, but anyway - something like this? Oops - edited...
SELECT po.id po_id
, po.order_quantity po_order_quantity
, po.applicable_approved_unit_rate po_unit_rate
, po.applicable_sales_tax_rate po_tax_rate
, po.order_date po_order_date
, po.remarks po_remarks
, po.is_open po_is_open
, po.is_active po_is_active
, po.approved_rate_id po_app_rate_id
, s.name sup_name
, SUM(do.quantity) total_ordered
FROM purchaseorder po
LEFT
JOIN deliveryorder do
ON do.purchase_order_id = po.
AND do.is_active = 1
LEFT
JOIN approvedrate ar
ON ar.id = po.approved_rate_id
AND ar.material_id = 2
LEFT
JOIN supplier s
ON s.id = ar.supplier_id
WHERE po.is_active = 1
AND po.is_open = 1
HAVING po.order_quantity >= total_ordered + 1
I couldn't work out how to get the desired results all in one query, but ended up using the following two queries to fulfill my requirements: -
1st query
SELECT
pot.`id` AS `po_id`,
pot.`order_quantity` AS `po_order_quantity`,
pot.`applicable_approved_unit_rate` AS `po_unit_rate`,
pot.`applicable_sales_tax_rate` AS `po_tax_rate`,
pot.`is_open` AS `po_is_open`,
pot.`is_active` AS `po_is_active`,
st.`id` AS `sup_id`,
st.`name` AS `sup_name`,
SUM(dot.`quantity`) AS `total_ordered`
FROM `purchaseorder` pot
INNER JOIN `deliveryorder` dot ON (dot.`purchase_order_id` = pot.`id`)
INNER JOIN `approvedrate` art ON (pot.`approved_rate_id` = art.`id`)
INNER JOIN `supplier` st ON (art.`supplier_id` = st.`id`)
WHERE (
pot.`is_active` = 1
AND pot.`is_open` = 1
AND art.`material_id` = #materialid
AND art.`in_effect` = 1
AND art.`is_active` = 1
AND dot.`is_active` = 1
AND st.`is_active` = 1
)
HAVING pot.`order_quantity` >= `total_ordered` + #materialquantity
2nd query
SELECT
pot.`id` AS `po_id`,
pot.`order_quantity` AS `po_order_quantity`,
pot.`applicable_approved_unit_rate` AS `po_unit_rate`,
pot.`applicable_sales_tax_rate` AS `po_tax_rate`,
pot.`is_open` AS `po_is_open`,
pot.`is_active` AS `po_is_active`,
st.`id` AS `sup_id`,
st.`name` AS `sup_name`,
0 AS `total_ordered`
FROM `purchaseorder` pot
INNER JOIN `approvedrate` art ON (pot.`approved_rate_id` = art.`id`)
INNER JOIN `supplier` st ON (art.`supplier_id` = st.`id`)
WHERE (
pot.`is_active` = 1
AND pot.`is_open` = 1
AND art.`material_id` = #materialid
AND art.`in_effect` = 1
AND art.`is_active` = 1
AND st.`is_active` = 1
AND pot.`order_quantity` >= #materialquantity
AND pot.`id` NOT IN
(
SELECT dot.`purchase_order_id`
FROM `deliveryorder` dot
WHERE dot.is_active = 1
)
)

MySQL >, <, and missing by group

I have two tables in MySQL that I'm comparing with the following attributes:
tbl_fac : facility_id, chemical_id, criteria
10 , 25 , 50
10 , 26 , 60
10 , 27 , 60
11 , 25 , 30
11 , 27 , 31
etc...
tbl_samp: sample_id, chemical_id, result
5 , 25 , 51
5 , 26 , 61
6 , 25 , 51
6 , 26 , 61
6 , 27 , 500
etc....
These tables are joined by chemical_id (many-to-many---- ugh), and there are several thousand facility_id's, and several hundred chemical_id's for each facility_id. There are also several thousand sample_id's, each with several hundred chemical_id's for each sample_id. All-in-all, there are around 500,000 records in tbl_fac, and 1,000,000+ records in tbl_samp.
I'm trying to extract three groups of sample_id's from this dataset:
Group 1: any sample_id where tbl_samp.result > tbl_fac.criteria (i.e., result exceeds criteria)
Group 2: any sample_id where tbl_samp.result < tbl_fac.criteria, AND all tbl_fac.chemical_id's are present for that sample_id (i.e., result is less than criteria, and everything is there)
Group 3: any sample_id where tbl_samp.result < tbl_fac.criteria, BUT one or more tbl_fac.chemical_id's are missing in the sample_id (i.e., result is less than criteria, but something is missing)
Here's the Question: How do I get all three Groups efficiently in one query?
I've tried:
select *
from tbl_fac
left join tbl_samp
on tbl_fac.chemical_id = tbl_samp.chemical_id
But this only yields values that are missing for the entire dataset (not the individual samples). I have a hackish query working that uses a third table to join tbl_fac and tbl_samp, but it is so ugly I'm actually embarrassed to post it....
As always, many thanks in advance for your thoughts on this one!
Cheers,
Josh
EDIT: Ideally, I would like the sample_id and Group returned -- with just one Group per sample ID (my knowledge of the data indicates that they will always fall into one of the three categories above).
This answer makes the assumption that there is a unique constraint on facility_id and chemical_id in tbl_fac and a unique constraint on sample_id and chemical_id in tbl_samp. What I did was build up the query one step at a time. Whether this is efficient remains to be seen.
Group 1: any sample_id where tbl_samp.result > tbl_fac.criteria (i.e., result exceeds criteria)
SELECT tbl_samp.sample_id,
'ResultsGreaterThanCriteria' AS samplegroup
FROM tbl_fac
INNER JOIN tbl_samp
ON tbl_fac.chemical_id = tbl_samp.chemical_id
WHERE tbl_samp.result > tbl_fac.criteria
GROUP BY tbl_samp.sample_id
Group 2: any sample_id where tbl_samp.result < tbl_fac.criteria, AND all tbl_fac.chemical_id's are present for that sample_id (i.e., result is less than criteria, and everything is there)
SELECT tbl_samp.sample_id,
'ResultLessThanCriteriaAndAllChems' AS samplegroup
FROM tbl_fac
INNER JOIN tbl_samp
ON tbl_fac.chemical_id = tbl_samp.chemical_id
WHERE tbl_samp.result < tbl_fac.criteria
AND NOT EXISTS (SELECT *
FROM tbl_fac tf
LEFT JOIN tbl_samp ts
ON tf.chemical_id = ts.chemical_id
WHERE ts.chemical_id IS NULL
AND tbl_samp.sample_id = ts.sample_id)
GROUP BY tbl_samp.sample_id
Group 3: any sample_id where tbl_samp.result < tbl_fac.criteria, BUT one or more tbl_fac.chemical_id's are missing in the sample_id (i.e., result is less than criteria, but something is missing)
SELECT tbl_samp.sample_id,
'ResultsLessThanCriteriaWithMissingChems' AS samplegroup
FROM tbl_fac
INNER JOIN tbl_samp
ON tbl_fac.chemical_id = tbl_samp.chemical_id
WHERE tbl_samp.result < tbl_fac.criteria
AND EXISTS (SELECT *
FROM tbl_fac tf
LEFT JOIN tbl_samp ts
ON tf.chemical_id = ts.chemical_id
WHERE ts.chemical_id IS NULL
AND tbl_samp.sample_id = ts.sample_id)
GROUP BY tbl_samp.sample_id
And finally, you union all three queries together and get:
SELECT tbl_samp.sample_id,
'ResultsGreaterThanCriteria' AS samplegroup
FROM tbl_fac
INNER JOIN tbl_samp
ON tbl_fac.chemical_id = tbl_samp.chemical_id
WHERE tbl_samp.result > tbl_fac.criteria
GROUP BY tbl_samp.sample_id
UNION ALL
SELECT tbl_samp.sample_id,
'ResultLessThanCriteriaAndAllChems' AS samplegroup
FROM tbl_fac
INNER JOIN tbl_samp
ON tbl_fac.chemical_id = tbl_samp.chemical_id
WHERE tbl_samp.result < tbl_fac.criteria
AND NOT EXISTS (SELECT *
FROM tbl_fac tf
LEFT JOIN tbl_samp ts
ON tf.chemical_id = ts.chemical_id
WHERE ts.chemical_id IS NULL
AND tbl_samp.sample_id = ts.sample_id)
GROUP BY tbl_samp.sample_id
UNION ALL
SELECT tbl_samp.sample_id,
'ResultsLessThanCriteriaWithMissingChems' AS samplegroup
FROM tbl_fac
INNER JOIN tbl_samp
ON tbl_fac.chemical_id = tbl_samp.chemical_id
WHERE tbl_samp.result < tbl_fac.criteria
AND EXISTS (SELECT *
FROM tbl_fac tf
LEFT JOIN tbl_samp ts
ON tf.chemical_id = ts.chemical_id
WHERE ts.chemical_id IS NULL
AND tbl_samp.sample_id = ts.sample_id)
GROUP BY tbl_samp.sample_id
SELECT
sample_id,
IF(result = criteria, -1, /* unspecified behavior */
IF(result > criteria, 1,
IF(nb_chemicals = total_nb_chemicals, 2, 3))) AS grp
FROM (
SELECT s.result, s.sample_id, f.criteria, f.chemical_id,
COUNT(DISTINCT f.chemical_id) AS nb_chemicals
FROM tbl_fac f JOIN tbl_samp s
ON f.chemical_id = s.chemical_id
GROUP BY s.sample_id
) t
CROSS JOIN (
SELECT COUNT(DISTINCT chemical_id) AS total_nb_chemicals
FROM tbl_fac
) u
New solution:
SELECT
s.sample_id,
IF(s.result = f.criteria, -1, /* unspecified behavior */
IF(s.result > f.criteria, 1,
IF(sample_nb_chemicals = total_nb_chemicals, 2, 3))) AS grp
FROM
tbl_fac f JOIN tbl_samp s
ON f.chemical_id = s.chemical_id
JOIN (
SELECT s.sample_id,
COUNT(DISTINCT f.chemical_id) AS sample_nb_chemicals
FROM tbl_fac f JOIN tbl_samp s
ON f.chemical_id = s.chemical_id
GROUP BY s.sample_id
) u
ON s.sample_id = u.sample_id
CROSS JOIN (
SELECT COUNT(DISTINCT chemical_id) AS total_nb_chemicals
FROM tbl_fac
) v
GROUP BY sample_id, grp

MySQL query returning 0 rows while it should return one

Something is wrong with my MySQL query below but I can't find the problem. It's not returning any errors but the query below should return 1 row, but it returns none.
The table 'fws_product' contains all products. The table 'webits_product_has_kenmerken' contains the product specifications.
SELECT fws_product.*
FROM webits_product_has_kenmerken
LEFT JOIN fws_product ON webits_product_has_kenmerken.product_id = fws_product.ID
WHERE fws_product.CATID = 11
AND (
(webits_product_has_kenmerken.kenmerk_id = 8 AND webits_product_has_kenmerken.kenmerk_value = 'Buddha to Buddha')
AND
(webits_product_has_kenmerken.kenmerk_id = 19 AND webits_product_has_kenmerken.kenmerk_value = '10 mm')
)
Thanks in advance!
It looks a bit nasty, but the following should do as you have requested
SELECT
p.*
FROM fws_product AS p
INNER JOIN webits_product_has_kenmerken AS ps8
ON ps8.product_id = p.ID
AND ps8.kenmerk_id = 8
AND ps8.kenmark_value = 'Buddha to Buddha'
INNER JOIN webits_product_has_kenmerken AS ps19
ON ps19.product_id = p.ID
AND ps19.kenmerk_id = 19
AND ps19.kenmark_value = '10 mm'
WHERE p.CATID = 11
This is another potential option which may do the job, but still feels very nasty
SELECT
p.*
FROM fws_product AS p
INNER JOIN (
SELECT
product_id,
COUNT(*) AS numMatches
FROM webits_product_has_kenmerken
WHERE (kenmerk_id,kenmerk_value) IN (
(8,'Buddha to Buddha'),
(19,'10 mm')
)
GROUP BY product_id
HAVING numMatches = 2
) AS ps
ON ps.product_id = p.ID
WHERE p.CATID = 11
i think you need the following:
SELECT fws_product.*
FROM webits_product_has_kenmerken
LEFT JOIN fws_product ON webits_product_has_kenmerken.product_id = fws_product.ID
WHERE fws_product.CATID = 11
AND (
(webits_product_has_kenmerken.kenmerk_id = 8 AND webits_product_has_kenmerken.kenmerk_value = 'Buddha to Buddha')
OR
(webits_product_has_kenmerken.kenmerk_id = 19 AND webits_product_has_kenmerken.kenmerk_value = '10 mm')
)
checke these columns for NULL values:
fws_product.CATID
webits_product_has_kenmerken.kenmerk_id
webits_product_has_kenmerken.kenmerk_value
every comparison with NULL will exclude the row from the reult

MySQL JOIN WHERE forgein Key = id1 AND forgein Key = id2

I am having a bit of a brain block with this problem and I am finding it hard to search for a solution because I cant phrase the question correctly to bring up the relevant information.
I am trying to get back "fProduct" record from the table below where it has a "fAttribute"
of 2 and 20.
id fAttribute fProduct
19 2 2967
48 2 2923
50 2 3008
51 20 3008
52 2 2295
53 20 2295
My statment below produces 0 results when I would expect to return fProduct's 2295 and 3008.
SELECT fProduct
FROM tableName
WHERE fAttribute = 2 AND fAttribute = 20
GROUP BY fProduct
Can anyone help please?
You can either use INNER JOINS or use EXISTS conditions:
INNER JOIN:
SELECT DISTINCT a.fProduct
FROM MyTable a
INNER JOIN MyTable b ON a.fProduct = b.fProduct AND b.fAttribute = 2
INNER JOIN MyTable c ON a.fProduct = c.fProduct AND c.fAttribute = 20
EXISTS:
SELECT afproduct
FROM MyTable a
WHERE EXISTS (SELECT b.id FROM MyTable b WHERE a.fProduct = b.fProduct AND b.fAttribute = 2)
AND EXISTS (SELECT c.id FROM MyTable c WHERE a.fProduct = c.fProduct AND c.fAttribute = 20)
A join should help:
SELECT distinct a.fProduct
FROM tableName as a
join tableName as b on b.product = a.product
WHERE a.fAttribute = 2 and b.fAttribute = 20
Since your are already doing a GROUP BY just change your WHERE clause to an OR or an IN and add the HAVING COUNT(fattribute) = 2 which makes sure it has both.
SELECT fproduct
FROM tablename
WHERE fattribute IN (2 , 20)
GROUP BY fproduct
HAVING COUNT(fattribute) = 2