I have the following query:
SELECT c.danhoEstetico, c.danhoDirecto
FROM conceptos c
INNER JOIN materialesconceptos mc ON mc.idConcepto = c.idConcepto
INNER JOIN materiales m ON m.idMaterial = mc.idMaterial
WHERE m.idMaterial IN (4,11,11)
Which yields the following result (for example):
danhoEstetico | danhoDirecto
1 | 0
1 | 0
0 | 0
0 | 0
I need to make a query that gives me if any of the items in each column has a 1, like an OR among all the fields in the same column, with an output like:
danhoEstetico | danhoDirecto
1 | 0
I have tried:
SELECT
SUM(CASE c.danhoEstetico WHEN c.danhoEstetico=1 THEN 1 ELSE 0 END) AS de,
SUM(CASE c.danhoDirecto WHEN c.danhoDirecto=1 THEN 1 ELSE 0 END) AS dd
FROM conceptos c INNER JOIN materialesconceptos mc ON mc.idConcepto = c.idConcepto
INNER JOIN materiales m ON m.idMaterial = mc.idMaterial
WHERE m.idMaterial IN (4,11,11)
Which, for some reason, yields:
danhoEstetico | danhoDirecto
4 | 4
Any hint on this?
To get the largest value in each column, use MAX instead of SUM.
Edit: I misread the question. This solution checks that every row in a column is 1, rather than any row. I recommend CL's answer, but I will leave this answer here because it explains a problem with the CASE statement in the question.
You should be using CASE without a base expression:
SELECT
SUM(CASE WHEN c.danhoEstetico=1 THEN 1 ELSE 0 END) AS de,
SUM(CASE WHEN c.danhoDirecto=1 THEN 1 ELSE 0 END) AS dd
FROM conceptos c INNER JOIN materialesconceptos mc ON
mc.idConcepto = c.idConcepto
INNER JOIN materiales m ON m.idMaterial = mc.idMaterial
WHERE m.idMaterial IN (4,11,11)
From the documentation:
In a CASE with a base expression, the base expression is evaluated
just once and the result is compared against the evaluation of each
WHEN expression from left to right. The result of the CASE expression
is the evaluation of the THEN expression that corresponds to the first
WHEN expression for which the comparison is true...
In your statement as written, the case statement always evaluated to 1 when the column was 1 and 0 when the column was 0. Thus, they always matched, and the sum was always the number of rows.
Update: now how do you actually turn this into the result you want? Here is one way:
SELECT
SUM(CASE WHEN c.danhoEstetico=1 THEN 1 ELSE 0 END) / SUM(1) AS de,
SUM(CASE WHEN c.danhoDirecto=1 THEN 1 ELSE 0 END) / SUM(1) AS dd
FROM conceptos c INNER JOIN materialesconceptos mc ON
mc.idConcepto = c.idConcepto
INNER JOIN materiales m ON m.idMaterial = mc.idMaterial
WHERE m.idMaterial IN (4,11,11)
This takes advantage of integer arithmetic. The division will result in a value < 1 if not all rows in a column are one, and a value less than one will show as zero.
select distinct
c.danhoEstetico, c.danhoDirecto
FROM conceptos c
INNER JOIN materialesconceptos mc ON mc.idConcepto = c.idConcepto
INNER JOIN materiales m ON m.idMaterial = mc.idMaterial
where 1 in (c.danhoEstetico , c.danhoDirecto)
Related
This question already has answers here:
Two SQL LEFT JOINS produce incorrect result
(3 answers)
Closed 9 months ago.
I may have messed up the joins or there may be another way of writing what I am trying to achieve.
My current query is this:
SELECT
i.SKI_NAME AS Description,
l.SKV_QUANTITY_IN_STOCK AS Qty,
SUM(CASE WHEN ad.AVN_STATUS = 'D' THEN li.AVL_QUANTITY ELSE '0' END) AS AdviceQty,
SUM(CASE WHEN con.HCT_STATUS = 'D' THEN item.HIT_QUANTITY ELSE '0' END) AS HireQty
FROM
TH_STOCK_LEVELS l
LEFT JOIN TH_STOCK_ITEMS i ON l.SKV_STOCK_NUMBER = i.SKI_STOCK_NUMBER
LEFT JOIN TH_ADVICE_NOTE_LINES li ON i.SKI_NAME = li.AVL_DESCRIPTION
LEFT JOIN TH_HIRE_ITEMS Item ON li.AVL_DESCRIPTION = Item.HIT_DESCRIPTION
LEFT JOIN TH_ADVICE_NOTES ad ON ad.AVN_ID = li.AVL_NOTE_NUMBER
LEFT JOIN TH_HIRE_CONTRACTS con ON con.HCT_CONTRACT_NUMBER = Item.HIT_CONTRACT_NUMBER
WHERE
l.SKV_DEPOT_ID = 7
GROUP BY i.SKI_NAME, l.SKV_QUANTITY_IN_STOCK;
This displays the following output:
Description
Qty
AdviceQty
HireQty
Some Item
2
400
100
Some Item
0
100
0
Which is incorrect, as it seems to be totalling all previous Advice's and Hire's and not just the ones with Status 'D'.
If I do the following to the query (comment some lines out):
SELECT
i.SKI_NAME AS Description,
l.SKV_QUANTITY_IN_STOCK AS Qty,
SUM(CASE WHEN ad.AVN_STATUS = 'D' THEN li.AVL_QUANTITY ELSE '0' END) AS AdviceQty
--SUM(CASE WHEN con.HCT_STATUS = 'D' THEN item.HIT_QUANTITY ELSE '0' END) AS HireQty
FROM
TH_STOCK_LEVELS l
LEFT JOIN TH_STOCK_ITEMS i ON l.SKV_STOCK_NUMBER = i.SKI_STOCK_NUMBER
LEFT JOIN TH_ADVICE_NOTE_LINES li ON i.SKI_NAME = li.AVL_DESCRIPTION
--LEFT JOIN TH_HIRE_ITEMS Item ON li.AVL_DESCRIPTION = Item.HIT_DESCRIPTION
LEFT JOIN TH_ADVICE_NOTES ad ON ad.AVN_ID = li.AVL_NOTE_NUMBER
--LEFT JOIN TH_HIRE_CONTRACTS con ON con.HCT_CONTRACT_NUMBER = Item.HIT_CONTRACT_NUMBER
WHERE
l.SKV_DEPOT_ID = 7
GROUP BY i.SKI_NAME, l.SKV_QUANTITY_IN_STOCK;
The output is correct, although I am now missing a column due to the comments. This also works if I comment out the Advice tables, the HireQty column would be correct.
Description
Qty
AdviceQty
Some Item
2
10
Some Item
0
0
How do I get this to display the correct data for both AdviceQty & HireQty without having to do them separately?
Sometimes, CASE statement doesn't work. You can try with IFs and see if it is working.
SELECT
i.SKI_NAME AS Description,
l.SKV_QUANTITY_IN_STOCK AS Qty, SUM(IF(ad.AVN_STATUS='D',li.AVL_QUANTITY,0)) AS AdviceQty, SUM(IF(con.HCT_STATUS='D',item.HIT_QUANTITY,0)) AS HireQty
FROM
TH_STOCK_LEVELS l
LEFT JOIN TH_STOCK_ITEMS i ON l.SKV_STOCK_NUMBER = i.SKI_STOCK_NUMBER LEFT JOIN TH_ADVICE_NOTE_LINES li ON i.SKI_NAME = li.AVL_DESCRIPTION LEFT JOIN TH_HIRE_ITEMS Item ON li.AVL_DESCRIPTION
= Item.HIT_DESCRIPTION LEFT JOIN TH_ADVICE_NOTES ad ON ad.AVN_ID = li.AVL_NOTE_NUMBER LEFT JOIN TH_HIRE_CONTRACTS con ON con.HCT_CONTRACT_NUMBER = Item.HIT_CONTRACT_NUMBER
WHERE
l.SKV_DEPOT_ID = 7
GROUP BY i.SKI_NAME, l.SKV_QUANTITY_IN_STOCK;
I have query with joins (in magento) :
SELECT FLOOR(rating.rating_summary/20) AS `rating_value`,
COUNT(*) AS `count`
FROM `catalog_product_flat_3` AS `e`
INNER JOIN `catalogsearch_result` AS `search_result` ON search_result.product_id=e.entity_id
AND search_result.query_id='218'
INNER JOIN `catalog_product_index_price` AS `price_index` ON price_index.entity_id = e.entity_id
AND price_index.website_id = '1'
AND price_index.customer_group_id = 0
INNER JOIN `review_entity_summary` AS `rating` ON rating.entity_pk_value = e.entity_id
AND rating.store_id = 0;
It is required to filter out rows with NULL in rating_value or count < 1
+--------------+-------+
| rating_value | count |
+--------------+-------+
| NULL | 0 |
+--------------+-------+
1 row in set (0,00 sec)
but for some reason where i try WHERE count > 0 or rating_value IS NOT NULL it saids that subject column rating_value, count is not exists, what do I do wrong ?
Thank you!
Correct. A column alias defined in a SELECT cannot be used in the WHERE. You need a subquery or to repeat the expression:
WHERE FLOOR(rating.rating_summary/20) IS NOT NULL
This is equivalent to:
WHERE rating.rating_summary IS NOT NULL
The count needs to go in a HAVING clause, which I would write as:
HAVING count = 0 OR rating_value IS NOT NULL
I would also expect your query to have a GROUP BY clause, which it seems to be missing.
So I suspect you want:
SELECT FLOOR(rating.rating_summary/20) AS `rating_value`,
COUNT(*) AS `count`
FROM `catalog_product_flat_3` pf INNER JOIN
`catalogsearch_result` sr
ON sr.product_id = pf.entity_id AND
sr.query_id = 218 INNER JOIN
`catalog_product_index_price` pip
ON pip.entity_id = pf.entity_id AND
pip.website_id = 1 AND
pip.customer_group_id = 0 INNER JOIN
`review_entity_summary` r
ON r.entity_pk_value = pf.entity_id AND r.store_id = 0
GROUP BY FLOOR(r.rating_summary/20)
HAVING `count` = 0 OR rating_value IS NULL;
I have a sql statement with many inner join tables, as you can see below I have many conditional SUM statements , these sums are giving me wrong (very large) numbers as the inner join is repeating the same values in my source select pool. I was wondering id there is a way to limit these sum conditions lets say to EMPLIDs. The code is :
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
SUM(C.FACTOR_XSALARY) AS X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
COUNT(D.EMPLID),
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
(SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END)+SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END))*100/(COUNT(A.EMPLID)) AS PEpercent
FROM
EMP_DTL A INNER JOIN EMPL_CTG_L1 B ON A.EMPL_CTG = B.EMPL_CTG
INNER JOIN
ECM_PRYR_VW C ON A.EMPLID=C.EMPLID
INNER JOIN ECM_INELIG D on D.EMPL_CTG=A.EMPL_CTG and D.YEAR=YEAR(getdate())
WHERE
A.YEAR=YEAR(getdate())
AND B.EFF_STATUS='A'
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY B.DESCR
I already tried moving D.YEAR=YEAR(getdate()) to the where clause. Any help would be greatly appereciated
The probable reason of your very large numbers is probably due to the result of Cartesian product of joining A -> B, A -> C and A -> D where tables C and D appear to have multiple records. So, just example... if A has 10 records, and C has 10 for each of the A records, you now have 10 * 10 records... Finally, join that to D table with 10 records, you now have 10 * 10 * 10 for each "A", thus your bloated answers.
Now, how to resolve. I have taken your "C" and "D" tables and "Pre-Aggregated" those counts based on the join column basis. This way, they will each have only 1 record with the total already computed at that level, joined back to A table and you lose your Cartesian issue.
Now, for table B, it appears that is a lookup table only and would only be a single record result anyhow.
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
PreAggC.X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
PreAggD.DCount,
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
( SUM( CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END
+ CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END ) *
100 / COUNT(A.EMPLID) AS PEpercent
FROM
EMP_DTL A
INNER JOIN EMPL_CTG_L1 B
ON A.EMPL_CTG = B.EMPL_CTG
AND B.EFF_STATUS='A'
INNER JOIN ( select
C.EMPLID,
SUM(C.FACTOR_XSALARY) AS X_Programp
from
ECM_PRYR_VW C
group by
C.EMPLID ) PreAggC
ON A.EMPLID = PreAggC.EMPLID
INNER JOIN ( select
D.EMPLID,
COUNT(*) AS DCount
from
ECM_INELIG D
where
D.Year = YEAR( getdate())
group by
D.EMPLID ) PreAggD
ON A.EMPLID = PreAggD.EMPLID
WHERE
A.YEAR=YEAR(getdate())
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY
B.DESCR
select
tmp.templatedesc Template
,sec.name Section
,q.questiontext Questions,
--,sum(case when q.responserequired = '0' then 1 else null end) as 'N/A'
--,sum(case when q.responserequired = '1' then 1 else null end) as Scored
--,count (case when (qr.weightedscore is not null and tmp.templatedesc = 'QA 30 Day Call Form' and
--sec.name = 'opening' and
--rv.reviewstatusid = 1 )then 1 else null end) as scored
----,(case when qr.weightedscore <> q.weight then rv.reviewid else null end) as fail
--count (case when qr.weightedscore is null then 1 else null end) NA,
--count (case when qr.weightedscore is not null then 1 else null end) scored,
sec.sequencenumber, q.questionnumber, qr.*
from
aqm.dbo.reviewtemplate tmp (nolock)
inner join aqm.dbo.section sec on sec.templateid =tmp.templateid
inner join aqm.dbo.sectionresult scr on scr.sectionid = sec.sectionid
inner join aqm.dbo.questionresult qr on qr.sectionresultid = scr.sectionresultid
inner join aqm.dbo.question q on q.questionid = qr.questionid
--inner join aqm.dbo.questiontype qt on qt.questiontypeid = q.questiontypeid
--left outer join aqm.dbo.questionoption qo on qo.questionid = q.questionid
inner join aqm.dbo.review rv on tmp.templateid = rv.templateid
inner join aqm.dbo.media md on md.mediaid = rv.mediaid
inner join aqm.dbo.iqmuser ut on md.userid = ut.userid
where
rv.reviewstatusid = 1 and
tmp.templatedesc = 'QA 30 Day Call Form'
and sec.name = 'opening' and
convert(varchar,dateadd(hh,-7,rv.reviewdate), 101) = '07/07/2014'
and ut.windowslogonaccount = 'name.name'
and q.questionnumber = 4
--group by
--tmp.templatedesc , sec.name, q.questiontext, sec.sequencenumber, q.questionnumber
order by
sec.sequencenumber, q.questionnumber
the questionresultid and sectionresultid are returning multiple values
how can i fix the joins so that it doesnt return multiple values?
i have it drilled down to a date and a person so that it should only return one row of results( but that obviously didnt work)
not sure what other data i can provide
update
i think it has to do with joins
inner join aqm.dbo.sectionresult scr on scr.sectionid = sec.sectionid
inner join aqm.dbo.questionresult qr on qr.sectionresultid = scr.sectionresultid
as those are the ones returning multiple results.
just dont know how to fix it
First, neither aqm.dbo.questiontype nor aqm.dbo.questionoption are used in your return fields or your where clause so get rid of them if they aren't required.
Second, you are OUTER JOINing on the aqm.dbo.review, but the reviewstatusid and reviewdate are required in the WHERE clause - so this should probably be an INNER JOIN.
Last, best way to debug issues like this is to comment out the COUNT statements and the GROUP BY clause - and see what raw data is being returned.
i have a table campaign which has details of campaign mails sent.
campaign_table: campaign_id campaign_name flag
1 test1 1
2 test2 1
3 test3 0
another table campaign activity which has details of campaign activities.
campaign_activity: campaign_id is_clicked is_opened
1 0 1
1 1 0
2 0 1
2 1 0
I want to get all campaigns with flag value 3 and the number of is_clicked columns with value 1 and number of columns with is_opened value 1 in a single query.
ie. campaign_id campaign_name numberofclicks numberofopens
1 test1 1 1
2 test2 1 1
I did this using sub-query with the query:
select c.campaign_id,c.campaign_name,
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofclicks,
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofopens
FROM
campaign c
WHERE c.flag=1
But people say that using sub-queries are not a good coding convention and you have to use join instead of sub-queries. But i don't know how to get the same result using join. I consulted with some of my colleagues and they are saying that its not possible to use join in this situation. Is it possible to get the same result using joins? if yes, please tell me how.
This should do the trick. Substitute INNER JOIN for LEFT OUTER JOIN if you want to include campaigns which have no activity.
SELECT
c.Campaign_ID
, c.Campaign_Name
, SUM(CASE WHEN a.Is_Clicked = 1 THEN 1 ELSE 0 END) AS NumberOfClicks
, SUM(CASE WHEN a.Is_Opened = 1 THEN 1 ELSE 0 END) AS NumberOfOpens
FROM
dbo.Campaign c
INNER JOIN
dbo.Campaign_Activity a
ON a.Campaign_ID = c.Campaign_ID
GROUP BY
c.Campaign_ID
, c.Campaign_Name
Assuming is_clicked and is_opened are only ever 1 or 0, this should work:
select c.campaign_id, c.campaign_name, sum(d.is_clicked), sum(d.is_opened)
from campaign c inner join campaign_activity d
on c.campaign_id = d.campaign_id
where c.flag = 1
group by c.campaign_id, c.campaign_name
No sub-queries.
Hmm. Is what you want as simple as this? I'm not sure I'm reading the question right...
SELECT
campaign_table.campaign_id, SUM(is_clicked), SUM(is_opened)
FROM
campaign_table
INNER JOIN campaign_activity ON campaign_table.campaign_id = campaign_activity.campaign_id
WHERE
campaign_table.flag = 1
GROUP BY
campaign_table.campaign_id
Note that with an INNER JOIN here, you won't see campaigns where there's nothing corresponding in the campaign_activity table. In that circumstance, you should use a LEFT JOIN, and convert NULL to 0 in the SUM, e.g. SUM(IFNULL(is_clicked, 0)).
I suppose this should do it :
select * from campaign_table inner join campaign_activity on campaign_table.id = campaign_activity.id where campaign_table.flag = 3 and campaign_activity.is_clicked = 1 and campaign_activity.is_opened = 1
Attn : this is not tested in a live situation
The SQL in it's simplest form and most robust form is this: (formatted for readability)
SELECT
campaign_table.campaign_ID, campaign_table.campaign_name, Sum(campaign_activity.is_clicked) AS numberofclicks, Sum(campaign_activity.is_open) AS numberofopens
FROM
campaign_table INNER JOIN campaign_activity ON campaign_table.campaign_ID = campaign_activity.campaign_ID
GROUP BY
campaign_table.campaign_ID, campaign_table.campaign_name, campaign_table.flag
HAVING
campaign_table.flag=1;