SQL query - two select to one - mysql

How can I merge these two selects to one? As a result, I want column "POJ", "locked POJ" and "EV".
SELECT COUNT(VC) AS 'POJ', F.F_C.VC AS 'EV' FROM
F.F_D LEFT JOIN F.F_C ON F.F_D.col_id = F.F_C.id
LEFT JOIN F.F_Z_D ON F.F_D.id = F.F_Z_D.id
where createdTime >= '2021-05-01' and createdTime <= '2022-05-31' and tTemplate = 'ZS' GROUP BY F.F_C.VC;
SELECT COUNT(VC) AS 'locked POJ', F.F_C.VC AS 'EV' FROM
F.F_D LEFT JOIN F.F_C ON F.F_D.col_id = F.F_C.id
LEFT JOIN F.F_Z_D ON F.F_D.id = F.F_Z_D.id
where createdTime >= '2021-05-01' and createdTime <= '2022-05-31' and tTemplate = 'ZS' and locked = 1 GROUP BY F.F_C.VC;

Use conditional aggregation:
SELECT COUNT(VC) AS POJ, SUM(locked = 1) AS `locked POJ`, F.F_C.VC AS EV
FROM F.F_D
LEFT JOIN F.F_C ON F.F_D.col_id = F.F_C.id
LEFT JOIN F.F_Z_D ON F.F_D.id = F.F_Z_D.id
WHERE createdTime BETWEEN '2021-05-01' AND '2022-05-31' AND tTemplate = 'ZS'
GROUP BY F.F_C.VC;
Note that the only difference between the two queries is that the second one has the additional criterion locked = 1 in the WHERE clause. We can remove it and use the first query, along with a conditional count.

Related

MySQL LEFT JOIN ignores AND criteria

I have a functional LEFT JOIN MySQL query structured like this:
SELECT
COUNT(HTG_ScheduleRequest.ID) AS current_job,
HTG_TechProps.EmpNumber,
HTG_TechProps.EmpFirstName,
HTG_TechProps.EmpLastName,
HTG_TechProps.Veh_Number
FROM HTG_TechProps
LEFT JOIN HTG_ScheduleRequest ON HTG_TechProps.EmpNumber = HTG_ScheduleRequest.SSR
AND (HTG_ScheduleRequest.ScheduleDateCurrent = CURDATE() || HTG_ScheduleRequest.ScheduleDateExact = CURDATE())
AND RecordType = '1'
AND HTG_ScheduleRequest.JobStatus IN (2,5,8,3,4,7)
GROUP BY HTG_TechProps.EmpNumber ORDER BY HTG_TechProps.EmpNumber ASC
I need to add some criteria to the initial SELECT table like this:
HTG_TechProps.EmpStatus='A'
I get a Syntax error when I add a WHERE statement prior to the LEFT JOIN and when I add an AND like this after the LEFT JOIN it is ignored an still returning records that are not equal to A.
LEFT JOIN HTG_ScheduleRequest ON HTG_TechProps.EmpNumber = HTG_ScheduleRequest.SSR
AND HTG_TechProps.EmpStatus='A'
Conditions on the first table in a LEFT JOIN should go in a WHERE clause:
SELECT COUNT(sr.ID) AS current_job,
tp.EmpNumber, tp.EmpFirstName, tp.EmpLastName, tp.Veh_Number
FROM HTG_TechProps tp LEFT JOIN
HTG_ScheduleRequest sr
ON tp.EmpNumber = sr.SSR AND
(sr.ScheduleDateCurrent = CURDATE() OR sr.ScheduleDateExact = CURDATE()
) AND
sr.RecordType = '1' AND -- assume this comes from SR
sr.JobStatus IN (2, 5, 8, 3, 4, 7)
WHERE tp.EmpStatus='A'
GROUP BY tp.EmpNumber -- this is okay assuming that it is unique or (equivalently) a primary key
ORDER BY tp.EmpNumber ASC;
Note that this introduces table aliases so the query is easier to write and to read.
You should Use OR
SELECT
COUNT(HTG_ScheduleRequest.ID) AS current_job,
HTG_TechProps.EmpNumber,
HTG_TechProps.EmpFirstName,
HTG_TechProps.EmpLastName,
HTG_TechProps.Veh_Number
FROM HTG_TechProps
LEFT JOIN HTG_ScheduleRequest ON HTG_TechProps.EmpNumber = HTG_ScheduleRequest.SSR
AND (HTG_ScheduleRequest.ScheduleDateCurrent = CURDATE() OR HTG_ScheduleRequest.ScheduleDateExact = CURDATE())
AND RecordType = '1'
AND HTG_ScheduleRequest.JobStatus IN (2,5,8,3,4,7)
GROUP BY HTG_TechProps.EmpNumber
ORDER BY HTG_TechProps.EmpNumber ASC
and if you want apply where condtion for main table's columns you could use where eg:
SELECT
COUNT(HTG_ScheduleRequest.ID) AS current_job,
HTG_TechProps.EmpNumber,
HTG_TechProps.EmpFirstName,
HTG_TechProps.EmpLastName,
HTG_TechProps.Veh_Number
FROM HTG_TechProps
LEFT JOIN HTG_ScheduleRequest ON HTG_TechProps.EmpNumber = HTG_ScheduleRequest.SSR
AND HTG_ScheduleRequest.JobStatus IN (2,5,8,3,4,7)
WHERE (HTG_ScheduleRequest.ScheduleDateCurrent = CURDATE() OR HTG_ScheduleRequest.ScheduleDateExact = CURDATE())
AND HTG_TechProps.RecordType = '1'
GROUP BY HTG_TechProps.EmpNumber
ORDER BY HTG_TechProps.EmpNumber ASC

How to combine two sql counts from same joined table

another annoying student here!
Today I spend hours trying to combine (select) 2 already joined SQL outputs + the ID of the original table in a single table output. which ultimately resulted in this query:
SELECT * FROM(
SELECT fd1.User_idUser,avg(fd1.caloryIntake)
AS 'workdays'
FROM fact_dailysnapshot fd1
INNER JOIN dim_day dd1 ON dd1.DATE_SK = fd1.DATE_SK
WHERE dd1.weekend_ind = 'N'
GROUP BY fd1.User_idUser
ORDER BY fd1.User_idUser) A,
(SELECT avg(fd1.caloryIntake) AS 'weekend'
FROM fact_dailysnapshot fd1
INNER
JOIN dim_day dd1 ON dd1.DATE_SK = fd1.DATE_SK
WHERE dd1.weekend_ind = 'Y'
GROUP BY fd1.User_idUser
ORDER BY fd1.User_idUser) B;
Which translates into…
Now this is a false result, the second column gives an almost constant value for all user entries. I think this must be solved with some kind of EXTRA join but I literally ran out of ideas. Thanks in advance..!
Your JOIN is missing an ON clause to relate dUser_idUser.
But, the simplest way to write the query uses conditional aggregation:
SELECT fd1.User_idUser,
avg(case when dd1.weekend_ind = 'N' then fd1.caloryIntake end) as weekday_avg,
avg(case when dd1.weekend_ind = 'Y' then fd1.caloryIntake end) as weekend_avg
FROM fact_dailysnapshot fd1 INNER JOIN
dim_day dd1
ON dd1.DATE_SK = fd1.DATE_SK
GROUP BY fd1.User_idUser
ORDER BY fd1.User_idUser;
This is one query instead of two.
If I understand correctly, this is what you are looking for:
SELECT A.User_idUser, A.workdays, B.weekend
FROM (
SELECT fd1.User_idUser, avg(fd1.caloryIntake) AS 'workdays'
FROM fact_dailysnapshot fd1
INNER JOIN dim_day dd1
ON dd1.DATE_SK = fd1.DATE_SK
WHERE dd1.weekend_ind = 'N'
GROUP BY fd1.User_idUser
ORDER BY fd1.User_idUser) A
JOIN
(SELECT fd1.User_idUser, avg(fd1.caloryIntake) AS 'weekend'
FROM fact_dailysnapshot fd1
INNER JOIN dim_day dd1
ON dd1.DATE_SK = fd1.DATE_SK
WHERE dd1.weekend_ind = 'Y'
GROUP BY fd1.User_idUser
ORDER BY fd1.User_idUser) B
ON A.User_idUser = B.User_idUser
Each query gives you all users by ID and their workdays or weekends. You need to JOIN the results of the two query on the user ID.

MySQL query sub query or grouping

Each modx_site_content record may have several records in modx_site_tmplvar_contentvalues.
I need to retrieve both modx_site_tmplvar_contentvalues.value where the tvv.tmplvarid = 3 AND the tvv.tmplvarid = 1. where tvv.tmplvarid is a future date, I need to return the tvv.value of tvv.tmplvarid 3 which is a comma separated list of tags.
This query does not return the values I need & I'm not sure how to get just what I want.
SELECT sc.id, sc.pagetitle, tvv.value, tvv.tmplvarid, tvv.id, tvv.value
FROM modx_site_content sc
left join modx_site_tmplvar_contentvalues tvv on tvv.contentid = sc.id
where published = '1'
and (tvv.tmplvarid = '3' and tvv.value >= curdate())
order by sc.id;
basically in the end I need to return only the list of tags (tvv.tmplvarid = 3) where the other associated record (tvv.tmplvarid = 1) is a date in the future.
Any thoughts, can this be done with grouping instead? I don't actually need anything from the modx_site_content table.
So you need to return the tags both rows in the modx_site_tmplvar_contentvalues table that has tmplvarid of 1 and 3 both related to the same modx_site_content, but only when the tmplvarid 3 row has a datetime field in the future?
I would do two separate joins to the modx_site_tmplvar_contentvalues tabe:
SELECT tOne.value, tThree.value
FROM modx_site_tmplvar_contentvalues tOne
INNER JOIN modx_site_content c ON tOne.contentid = c.id
INNER JOIN modx_site_tmplvar_contentvalues tThree ON tThree.contentid = c.id
WHERE c.published = 1
AND tOne.tmplvarid = 1
AND tThree.tmplvarid = 3 AND tThree.date > NOW()
SQL Fiddle: http://sqlfiddle.com/#!2/a4031/2
I figured it out. Amazing what you can do if you just read the docs ;)
select tv.contentid, tv.value as eventdate, sc.id, sc.pagetitle, tvv.value from
(
select * from modx_site_tmplvar_contentvalues cv
where cv.tmplvarid = 3
and cv.value >= curdate()
) as tv
left join modx_site_content sc on sc.id = tv.contentid
left join modx_site_tmplvar_contentvalues tvv on tvv.contentid = sc.id
where (tvv.tmplvarid = 1)
order by value asc

MySQL join only selected rows

SELECT invoices.number_formatted, SUM(invoices_elements.netto)
FROM invoices
LEFT JOIN invoices_elements ON invoices_elements_code_invoices_id = invoices_id
WHERE invoices_enable = 1
AND invoices_elements_enable = 1
GROUP BY invoices_elements_code_invoices_id
If table "invoices_elements" doesn't have any rows with "invoices_elements_enable = 1" this query return NULL - but i want "number formatted". So i do this:
SELECT SUM(netto)
FROM (invoices)
LEFT JOIN (SELECT * FROM invoices_elements WHERE invoices_elements_enable = 1) ON invoices_elements_code_invoices_id = invoices_id
WHERE invoices_enable = 1
GROUP BY invoices_elements_code_invoices_id
... and this of coz works. But - is better way to do it?
You can do
SELECT SUM(netto)
FROM invoices
LEFT JOIN invoices_elements
ON invoices_elements_code_invoices_id = invoices_id
AND invoices_elements_enable = 1
WHERE invoices_enable = 1
GROUP BY invoices_elements_code_invoices_id
Note the restriction invoices_elements_enable = 1 is in the ON clause to avoid converting the query into an inner join.

MySQL LIMIT in a Correllated Subquery

I have a correlated subquery that will return a list of quantities, but I need the highest quantity, and only the highest. So I tried to introduce an order by and a LIMIT of 1 to achieve this, but MySQL throws an error stating it doesn't yet support limits in subqueries. Any thoughts on how to work around this?
SELECT Product.Name, ProductOption.Name, a.Qty, a.Price, SheetSize.UpgradeCost,
FinishType.Name, FinishOption.Name, FinishTierPrice.Qty, FinishTierPrice.Price
FROM `Product`
JOIN `ProductOption`
ON Product.idProduct = ProductOption.Product_idProduct
JOIN `ProductOptionTier` AS a
ON a.ProductOption_idProductOption = ProductOption.idProductOption
JOIN `PaperSize`
ON PaperSize.idPaperSize = ProductOption.PaperSize_idPaperSize
JOIN `SheetSize`
ON SheetSize.PaperSize_idPaperSize = PaperSize.idPaperSize
JOIN `FinishOption`
ON FinishOption.Product_idProduct = Product.idProduct
JOIN `FinishType`
ON FinishType.idFinishType = FinishOption.Finishtype_idFinishType
JOIN `FinishTierPrice`
ON FinishTierPrice.FinishOption_idFinishOption = FinishOption.idFinishOption
WHERE Product.idProduct = 1
AND FinishTierPrice.idFinishTierPrice IN (SELECT FinishTierPrice.idFinishTierPrice
FROM `FinishTierPrice`
WHERE FinishTierPrice.Qty <= a.Qty
ORDER BY a.Qty DESC
LIMIT 1)
This is a variation of the greatest-n-per-group problem that comes up frequently.
You want the single row form FinishTierPrice (call it p1), matching the FinishOption and with the greatest Qty, but still less than or equal to the Qty of the ProductOptionTier.
One way to do this is to try to match a second row (p2) from FinishTierPrice that would have the same FinishOption and a greater Qty. If no such row exists (use an outer join and test that it's NULL), then the row found by p1 is the greatest.
SELECT Product.Name, ProductOption.Name, a.Qty, a.Price, SheetSize.UpgradeCost,
FinishType.Name, FinishOption.Name, FinishTierPrice.Qty, FinishTierPrice.Price
FROM `Product`
JOIN `ProductOption`
ON Product.idProduct = ProductOption.Product_idProduct
JOIN `ProductOptionTier` AS a
ON a.ProductOption_idProductOption = ProductOption.idProductOption
JOIN `PaperSize`
ON PaperSize.idPaperSize = ProductOption.PaperSize_idPaperSize
JOIN `SheetSize`
ON SheetSize.PaperSize_idPaperSize = PaperSize.idPaperSize
JOIN `FinishOption`
ON FinishOption.Product_idProduct = Product.idProduct
JOIN `FinishType`
ON FinishType.idFinishType = FinishOption.Finishtype_idFinishType
JOIN `FinishTierPrice` AS p1
ON p1.FinishOption_idFinishOption = FinishOption.idFinishOption
AND p1.Qty <= a.Qty
LEFT OUTER JOIN `FinishTierPrice` AS p2
ON p2.FinishOption_idFinishOption = FinishOption.idFinishOption
AND p2.Qty <= a.Qty AND (p2.Qty > p1.Qty OR p2.Qty = p1.Qty
AND p2.idFinishTierPrice > p1.idFinishTierPrice)
WHERE Product.idProduct = 1
AND p2.idFinishTierPrice IS NULL