Case With Having - sql

I have Plant, Material, Movement type and Date.
My requirement is I want the MAX date in Material and Plant combination, with Movement type condition
First I need MAX date in Material and Plant combination, where Movement type is 602 , if 602 is null then 601, if 601 is null then 102, if 102 is null then 101 if 101 also is null then other Movement types.
For this I used below code in derived table in IDT but I am not able to get the correct results:
SELECT
DISTINCT
Table__1."0PLANT",
Table__1."0MATERIAL",
Max(Table__1."0PSTNG_DATE") as Last_Sales_Date
FROM
"NM1"."PUBLIC"."IZDSO_DMR" Table__1
Where
CASE
WHEN (Table__1."0MOVETYPE"=602) THEN (Table__1."0MOVETYPE"=602)
WHEN (Table__1."0MOVETYPE"=602) IS NULL THEN (Table__1."0MOVETYPE"=601)
ELSE
(Table__1."0MOVETYPE"=601) END
Group By
Table__1."0MATERIAL",
Table__1."0PLANT"
I tried only for 602, 601 Movement types only
Please help me to get the correct result

This is your where clause:
Where (CASE WHEN (Table__1."0MOVETYPE"=602) THEN (Table__1."0MOVETYPE"=602)
WHEN (Table__1."0MOVETYPE"=602) IS NULL THEN (Table__1."0MOVETYPE"=601)
ELSE (Table__1."0MOVETYPE"=601)
END)
This will actually work with some SQL engines, because a comparison is turned into a number. However, I don't think this is what you want. You are looking to prioritize the max() value, based on the 0MoveType column.
SELECT "0PLANT", "0MATERIAL",
(case when sum(case when "0MOVETYPE" = 602 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 602 then "0PSTNG_DATE" end)
when sum(case when "0MOVETYPE" = 601 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 601 then "0PSTNG_DATE" end)
when sum(case when "0MOVETYPE" = 102 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 102 then "0PSTNG_DATE" end)
when sum(case when "0MOVETYPE" = 101 then 1 else 0 end) > 0
then max(case when "0MOVETYPE" = 101 then "0PSTNG_DATE" end)
end) as Last_Sales_Date
\FROM "NM1"."PUBLIC"."IZDSO_DMR" Table__1
Group By "0MATERIAL", "0PLANT";
This returns the last sales date for "602" if any are present. If none are present, then it returns the last sales date of "601". If neither "601" nor "602" are present, then it goes to "102" and so on.

Related

Invalid column name 'total_counted'

I'm querying the bin table to get the total active bins, total counted bins and calculate the percent of bins counted. Here's my query:
SELECT bin.location_id
,SUM(CASE WHEN bin.delete_flag = 'N' THEN 1 ELSE 0 END) AS total_active
,SUM(CASE WHEN bin.date_last_counted > 0 THEN 1 ELSE 0 END) AS total_counted
--,(total_counted / total_active) as pct_counted
From bin
Group by bin.location_id
Order by bin.location_id
When I try to use the code to create my pct_counted, it tells me "invalid column name" for both of the columns I'm using to calculate that value. Data looks like below.
location_id total_active total_counted
2 11502 484
6 2281 108
15 1772 253
Can anyone help?
You need to repeat the expressions (or use a subquery or CTE). I would recommend:
SELECT bin.location_id,
SUM(CASE WHEN bin.delete_flag = 'N' THEN 1 ELSE 0 END) AS total_active,
SUM(CASE WHEN bin.date_last_counted > 0 THEN 1 ELSE 0 END) AS total_counted
(SUM(CASE WHEN bin.date_last_counted > 0 THEN 1.0 ELSE 0 END) /
SUM(CASE WHEN bin.delete_flag = 'N' THEN 1 END)
) AS as pct_counted
FROM bin
GROUP BY bin.location_id
ORDER BY bin.location_id;
Note that I removed the ELSE clause for the second expression. This avoids divide-by-zero. The 1.0 also ensures decimal division even if your database does integer division.
I would format the sub-query this way:
Select
a.location_id
total_counted/total_active as pct_counted
from(select
bin.location_id
,SUM(CASE WHEN bin.delete_flag = 'N' THEN 1 ELSE 0 END) AS total_active
,SUM(CASE WHEN bin.date_last_counted > 0 THEN 1 ELSE 0 END) AS total_counted
From bin
Group by bin.location_id
Order by bin.location_id) a

How to nest a join into a complicated Select sum(case, group by statement

I am trying to generate a report, and so far have one completed that gives me how many orders, for each day, are in status 1-9.
TableA structure looks like this:
Sales Order | Order Status | Order Date
123456789 | 1 | 2017-02-22 00:00:00.000
123456790 | 0 | 2017-02-21 00:00:00.000
TableB structure looks like this:
Sales Order | Price
123456789 | 123.00
123456789 | 42.00
123456790 | 56.00
123456790 | 28.00
This code:
SELECT
MAX(year([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
Day([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN 1 ELSE 0 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN 1 ELSE 0 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN 1 ELSE 0 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN 1 ELSE 0 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN 1 ELSE 0 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN 1 ELSE 0 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN 1 ELSE 0 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN 1 ELSE 0 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN 1 ELSE 0 END) AS 'STATUS"/"'
FROM
SorMaster
WHERE
YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month, DateAdd(month, Month([OrderDate]) - 1, Cast('2008-01-01' AS Datetime))), Day([OrderDate])
ORDER BY
Yr DESC, M DESC, Day DESC
Returns this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 2 0 1 0 0 5 0 0
2017 2 21 0 0 0 7 0 0 0 0 0
This is PERFECT for my first report.
Now, comes the trouble. My Problem is that I need to nest-query Table B, so that instead of returning a count(orders), I need the sum(orders) those totals for each order are in Table B.
Using the above example, the query would need to return something like this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 165 0 0 0 0 0 0 0
2017 2 21 84 0 0 0 0 0 0 0 0
Any pointers?
Just join to TableB:
SELECT MAX(year([t1.OrderDate])) AS Yr,
MAX(MONTH([t2.OrderDate])) AS M,
DAY([t1.OrderDate]) AS Day,
SUM(CASE WHEN [OrderStatus] = '0' THEN t2.Price ELSE 0 END) AS 'STATUS"0"',
SUM(CASE WHEN [OrderStatus] = '1' THEN t2.Price ELSE 0 END) AS 'STATUS"1"',
SUM(CASE WHEN [OrderStatus] = '2' THEN t2.Price ELSE 0 END) AS 'STATUS"2"',
SUM(CASE WHEN [OrderStatus] = '4' THEN t2.Price ELSE 0 END) AS 'STATUS"4"',
SUM(CASE WHEN [OrderStatus] = '8' THEN t2.Price ELSE 0 END) AS 'STATUS"8"',
SUM(CASE WHEN [OrderStatus] = '9' THEN t2.Price ELSE 0 END) AS 'STATUS"9"',
SUM(CASE WHEN [OrderStatus] = 'S' THEN t2.Price ELSE 0 END) AS 'STATUS"S"',
SUM(CASE WHEN [OrderStatus] = '*' THEN t2.Price ELSE 0 END) AS 'STATUS"*"',
SUM(CASE WHEN [OrderStatus] = '/' THEN t2.Price ELSE 0 END) AS 'STATUS"/"'
FROM SorMaster t1
LEFT JOIN TableB t2
ON t1.[Sales Order] = t2.[Sales Order]
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY Yr DESC, M DEACLLSC, Day DESC
That's not too difficult, just a matter of LEFT JOINing in table B and then summing the prices in that. There's a couple of small tricks here. You want to LEFT JOIN to ensure that rows in table A always show up, even if there are no corresponding rows in table B. Secondly, in your SUM() statement, you'll need to add a COALESCE(...,0.00) to ensure you're summing decimals and no NULL values creep in from the LEFT JOIN. Oddly in databases, NULL + {anything} = NULL.
For the below query, you'll need to change the name of TableB to whatever the table name is, and the JOIN predicate will need to have the column names named accurately, and delimited correctly if they contain spaces. For example, in MSSQL the delimiters are [ and ], e.g. MyTable.[My Column With Spaces]
SELECT
MAX(YEAR([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
DAY([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"/"'
FROM SorMaster
LEFT OUTER JOIN TableB
ON TableB.SalesOrder = SorMaster.SalesOrder
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY
Yr DESC,
M DESC,
Day DESC
By (left) joining tableB and replacing your 'count' ones by tableB.price you should get the sum of all positions of orders with the according status.

Counting Values based on certain criteria SQL

I am trying to Write a View for some reporting in our CRM program and I'm having trouble with the counts. We are trying to count the number of referrals based on certain criteria. I feel like the way I wrote the view is incorrect. I am trying to use a CASE statement to make sure it counts the values that I want, but I the numbers I am getting I am not able to validate with reverse engineering.
Did I structure the CASE statement correctly?
(Note: I do realize that client is misspelled, unfortunately whoever wrote the database before I got it had some spelling issues.)
This is what I have written so far:
SELECT Comp_Name, Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Client' Then 1
ELSE NULL END) AS Client_Referrals,
Count(Case WHEN lead_companyprimaryreferralsource IS NOT NULL Then 1 Else Null End) AS Target_Referrals,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Prospect' Then 1 Else Null End) As Prospective_Client_Referral,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Lost_Clent' Then 1 Else Null End) AS Lost_Client_Referral,
Count(Case WHEN mcgr_companyid IS NOT NULL Then 1 Else NULL END) AS Intro_By_MCG
FROM Company
RIGHT JOIN Lead on Lead_PrimaryCompanyID = Comp_CompanyId
RIGHT JOIN MCGRelationships on mcgr_companyid = Comp_CompanyId
WHERE COMP_Name IS NOT NULL
Group By Comp_Name
Here is a Sample of What i'm getting:
Client1 0 0 0 0 1
Client2 0 0 0 0 2
Client3 0 0 0 0 1
Client4 0 0 0 0 1
Client5 0 0 0 0 2
Client6 0 0 0 0 2
Client7 0 0 4 0 4
Client8 0 0 0 0 2
Client9 0 2 2 0 2
Client10 12 6 0 0 12
Client11 0 0 0 0 2
When I just run a query on the table where Client 10 is the Primary Referral source, I get nothing. So I can't account for those 12 instances.
I think your problem may be in the join to MCGRelationships, if each company record can have more than one relationship record. If I'm following you correctly, you want Intro_By_MCG to be 1 if that record exists in MCGRelationships, regardless of the number of times it appears there. By joining the table, your query would be counting a lead once for each MCGRelationship associated with the company the lead comes from. Try this and let us know if the result is different:
SELECT Comp_Name, Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Client' Then 1
ELSE NULL END) AS Client_Referrals,
Count(Case WHEN lead_companyprimaryreferralsource IS NOT NULL Then 1 Else Null End) AS Target_Referrals,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Prospect' Then 1 Else Null End) As Prospective_Client_Referral,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Lost_Clent' Then 1 Else Null End) AS Lost_Client_Referral,
Count(Case WHEN EXISTS (Select Comp_CompanyId FROM MCGRelationships WHERE mcgr_companyid = Comp_CompanyId) Then 1 Else NULL END) AS Intro_By_MCG
FROM Company
RIGHT JOIN Lead on Lead_PrimaryCompanyID = Comp_CompanyId
WHERE COMP_Name IS NOT NULL
Group By Comp_Name

Multiple conditions in SQL

I have following table:
Employee ID Employee Status Date of Termination
1 A NULL
2 A NULL
3 I 1/1/2016
4 I 12/15/2016
5 I 1/1/2016
I would like to report on the following:
Number of current active employees - 2
Number of inactive employees - 3
Number of employees terminated in last one month - 2
This is the piece of code I used:
select
case when employee_status='A' then count(employee_id) else '' end,
case when employee_status='I' then count(employee_id) else '' end,
case when employee_status='I'
then
(select count(employee_id)
from employee
where date_of_termination between '1/1/2016' and '2/1/2016')
else '' end
from employee
My result set is:
Active | Inactive | Inactive_last_month
2 | 0 | 0
0 | 3 | 2
I would like to achieve the following:
Active | Inactive | Inactive_last_month
2 | 3 | 2
Any recommendations will be appreciated.
You need to SUM up the number of rows that match each criteria:
SELECT
SUM(CASE WHEN date_of_termination IS NULL THEN 1 ELSE 0 END) AS active,
SUM(CASE WHEN date_of_termination IS NOT NULL THEN 1 ELSE 0 END) AS inactive,
SUM(CASE WHEN date_of_termination BETWEEN '20160101' AND '20160201' THEN 1 ELSE 0 END) AS inactive_last_month
FROM
Employee
I've ignored the employee_status column with the assumption that the date is sufficient to determine whether or not the employee is active/inactive - in which case that column probably shouldn't even exist in the table since it's duplicating data.
This should be possible to simplify it using SUM :
select
sum(case when employee_status='A' then 1 else 0 end) as active,
sum(case when employee_status='I' then 1 else 0 end) as inactive,
sum(case when employee_status='I' and date_of_termination between '1/1/2016' and '2/1/2016' then 1 else 0 end) as inactive_last_month
from employee
I woudl wrap the case satements in sum() function and also modify the ELSE part of the CASE Statement to be 0.
so it will look like something like this:
select
SUM(case when employee_status='A' then count(employee_id) else 0 end) AS Active,
SUM(case when employee_status='I' then count(employee_id) else 0 end) AS Inactive,
SUM(case when employee_status='I'
then
(select count(employee_id)
from employee
where date_of_termination between '1/1/2016' and '2/1/2016')
else 0 end) AS Inactive_last_month
from employee

Querying Counts on Field Values in a Single Table

I have a single product table with multiple fields which contain user evaluations of various attributes:
product | attr_1_eval | attr_2_eval | attr_3_eval
ABC | Correct | Incorrect | Null
DEF | Incorrect | Null | Null
XYZ | Undetermined | Null | Incorrect
123 | Null | Undetermined | Correct
456 | Incorrect | Correct | Correct
I need to write a query which totals up those attribute evaluations across all products (where not null):
evaluation | correct | incorrect | undetermined
attr_1 | 1 | 2 | 1
attr_2 | 1 | 1 | 1
attr_3 | 2 | 1 | 0
This SQL gets me part way there:
SELECT
SUM(CASE WHEN attr_1_eval = 'Correct' then 1 else 0 END) AS correct,
SUM(CASE WHEN attr_1_eval = 'Incorrect' then 1 else 0 END) AS incorrect,
SUM(CASE WHEN attr_1_eval = 'Undetermined' then 1 else 0 END) AS undetermined,
SUM(CASE WHEN attr_2_eval = 'Correct' then 1 else 0 END) AS correct,
...
FROM product
But it doesn't group attr_1, attr_2.. by rows with error counts in the columns (as in the desired result set above). I'm using Postgres but help in any flavor of SQL would be most welcome.
Could you do 3 unions?
SELECT
'attr_1' AS evaluation,
SUM(CASE WHEN attr_1_eval = 'Correct' then 1 else 0 END) AS correct,
SUM(CASE WHEN attr_1_eval = 'Incorrect' then 1 else 0 END) AS incorrect,
SUM(CASE WHEN attr_1_eval = 'Undetermined' then 1 else 0 END) AS undetermined
FROM product
UNION
SELECT
'attr_2' AS evaluation,
SUM(CASE WHEN attr_2_eval = 'Correct' then 1 else 0 END) AS correct,
SUM(CASE WHEN attr_2_eval = 'Incorrect' then 1 else 0 END) AS incorrect,
SUM(CASE WHEN attr_2_eval = 'Undetermined' then 1 else 0 END) AS undetermined
FROM product
UNION
SELECT
'attr_3' AS evaluation,
SUM(CASE WHEN attr_3_eval = 'Correct' then 1 else 0 END) AS correct,
SUM(CASE WHEN attr_3_eval = 'Incorrect' then 1 else 0 END) AS incorrect,
SUM(CASE WHEN attr_3_eval = 'Undetermined' then 1 else 0 END) AS undetermined
FROM product
It's not the most elegant/efficient solution probably but it should get what you want
It's a little brute force, and I hate the fact that it scans the table three times, but this does appear to get the desired output. I'm sorry I don't know PostGres, but this should work in Oracle:
select
Attribute_name,
Sum (correct) as Correct,
sum (incorrect) as Incorrect,
sum (undetermined) as Undetermined
from
(
select
'attr_1' as Attribute_Name,
decode (attr_1_eval, 'Correct', 1, 0) as correct,
decode (attr_1_eval, 'Incorrect', 1, 0) as incorrect,
decode (attr_1_eval, 'Undetermined', 1, 0) as undetermined
from product
union all
select
'attr_2',
decode (attr_2_eval, 'Correct', 1, 0),
decode (attr_2_eval, 'Incorrect', 1, 0),
decode (attr_2_eval, 'Undetermined', 1, 0)
from product
union all
select
'attr_3',
decode (attr_3_eval, 'Correct', 1, 0),
decode (attr_3_eval, 'Incorrect', 1, 0),
decode (attr_3_eval, 'Undetermined', 1, 0)
from product
)
group by Attribute_Name