SQL query syntax in CASE WHEN ELSE END to count - sql

Writing a query to find the number of ED visits that were discharged from non-ED units.
The column dep.ADT_UNIT_TYPE_C column stores 1 if the unit was an ED unit.
Assume NULL values are non-ED units for the purpose of this query.
Which of the following produces this number?
I am thinking it is A because in my mind, that sound the correct syntax.
COUNT(CASE WHEN THEN ELSE END standard format)
A has that.
B doesn't have the THEN? so it is incorrect syntax?
Please help me understanding the nuances between these choices.
A.)
COUNT( CASE WHEN dep.ADT_UNIT_TYPE_C is NULL OR dep.ADT_UNIT_TYPE_C <> 1 THEN NULL
ELSE 1
END )
B.)
COUNT( CASE WHEN dep.ADT_UNIT_TYPE_C is NULL or dep.ADT_UNIT_TYPE_C <> 1
ELSE NULL
END)
C.)
CASE WHEN dep.ADT_UNIT_TYPE_C Is NULL or dep.ADT_UNIT_TYPE_C <> 1 THEN COUNT (NULL)
ELSE COUNT (1)
END
D.)
CASE WHEN dep.ADT_UNIT_TYPE_C is NULL or dep.ADT_UNIT_TYPE_C <> 1 THEN COUNT(1)
ELSE COUNT(NULL)
END

You can count the records that are returned COUNT(*) and put the condition in the where clause.
If you are using Oracle, you can use NVL.
The sample below is for Oracle, but if using mysql or SQL server, you can use the ISNULL Function.
SELECT COUNT(*) FROM dep WHERE NVL(ADT_UNIT_TYPE_C, 0) != 1
It looks like however, you are joining this to another table, probably a visit table. So, you want to count visits. Visits probably stores some kind of department id or way to join it to departments.
Something like this:
SELECT COUNT(*) FROM visit v, departments d WHERE v.dep_id = d.dep_id AND NVL(d.ADT_UNIT_TYPE_C, 0) !=1
If you want the entire list like shown above, you want to use a group by. This will show you the count for each visit by department type.
SELECT COUNT(*) FROM visit v, departments d GROUP BY d.ADT_UNIT_TYPE_C

Related

check and compare the count from two tables without relation

I have below tables
Table1: "Demo"
Columns: SSN, sales, Create_DT,Update_Dt
Table2: "Agent"
Columns: SSN,sales, Agent_Name, Create_Dt, Update_DT
Scenario 1 and desired result set:
I want output as 0 if the count of SSN in Demo table is matched with the count of SSN in Agent table
if the count is not matched then I want result as 1
Scenario 2 and desired result set:
I want output as 0 if the sum of sales in Demo table is matched with the sum of sales in Agent table
if the sum is not matched then I want result as 1
Please help on this query part
Thanks
You can write two queries separately to take counts within the result query
SELECT (SELECT count(Demo.SSN) as SSN1 from Demo)!=(SELECT count(Agent.SSN) as SSN2 from Agent) AS Result;
Basically what the inner queries does is it checked whether the counts are equal or not and outputs 1 if it is true and 0 if it is false. Since you have asked to output 1 if it is false I used '!=' sign.
You can try the same procedure in scenario 2 also
For scenario 1
select (Case when (select count(ssn) from Demo)=(select count(ssn) from Agent) then 0 else 1 end) as desired_result
If you want to count unique ssn then:
select (Case when (select count(distinct ssn) from Demo)=(select count(distinct ssn) from Agent) then 0 else 1 end) as desired_result
For scenario 2:
select (Case when (select sum(sales) from Demo)=(select sum(sales) from Agent) then 0 else 1 end) as desired_result
I would suggest one query with both sets of information:
select (d.num_ssn <> a.num_ssn) as have_different_ssn_count,
(d.sales <> a.sales) as have_different_sales
from (select count(distinct ssn) as num_ssn,
coalesce(sum(sales), 0) as sales
from demo
) d cross join
(select count(distinct ssn) as num_ssn,
coalesce(sum(sales), 0) as sales
from agent
) a;
Note: This returns boolean values -- true/false rather than 1/0. If you really want 0/1, then use case:
select (case when d.num_ssn <> a.num_ssn then 1 else 0 end) as have_different_ssn_count,
(case when d.sales <> a.sales then 1 else 0 end) as have_different_sales
It would not surprise me if you were not only interested in the total counts but also that the agent/sales combinations are the same in both tables. If that is the case, please ask a new question with a clear explanation. Sample data and desired results help.

Why does this not return 0

I have a query like:
select nvl(nvl(sum(a.quantity),0)-nvl(cc.quantityCor,0),0)
from RCV_TRANSACTIONS a
LEFT JOIN (select c.shipment_line_id,c.oe_order_line_id,nvl(sum(c.quantity),0) quantityCor
from RCV_TRANSACTIONS c
where c.TRANSACTION_TYPE='CORRECT'
group by c.shipment_line_id,c.oe_order_line_id) cc on (a.shipment_line_id=cc.shipment_line_id and a.shipment_line_id=7085740)
where a.transaction_type='DELIVER'
and a.shipment_line_id=7085740
group by nvl(cc.quantityCor,0);
The query runs OK, but returns no value. I want it to return 0 if there is no quantity found. Where have I gone wrong?
An aggregation query with a GROUP BY returns no rows if all rows are filtered out.
An aggregation query with no GROUP BY always returns one row, even if all rows are filtered out.
So, just remove the GROUP BY. And change the SELECT to:
select coalesce(sum(a.quantity), 0) - coalesce(max(cc.quantityCor), 0)
I may be wrong, but it seems you merely want to subtract CORRECT quantity from DELIVER quantity for shipment 7085740. You don't need a complicated query for that. Especially your GROUP BY clauses make no sense if that is what you are after.
One way to write this query would be:
select
sum(case when transaction_type = 'DELIVER' then quantity else 0 end) -
sum(case when transaction_type = 'CORRECT' then quantity else 0 end) as diff
from rcv_transactions
where shipment_line_id = 7085740;
I had a query like this and was trying to return 'X' when the item is not valid.
SELECT case when segment1 is not null then segment1 else 'X' end
--INTO v_orgValidItem
FROM mtl_system_items_b
WHERE segment1='1676001000'--'Jul-00'--l_item
and organization_id=168;
..but it was returning NULL.
Changed to use aggregation with no group by and now it returns 'X' when the item is not valid.
SELECT case when max(segment1) is not null then max(segment1) else 'X' end valid
--INTO v_orgValidItem
FROM mtl_system_items_b
WHERE segment1='1676001000'--'Jul-00'--l_item
and organization_id=168;--l_ship_to_organization_id_pb;
Here is another example, proving the order of operations really matters.
When there is no match for this quote number, this query returns NULL:
SELECT MAX(NVL(QUOTE_VENDOR_QUOTE_NUMBER,0))
FROM PO_HEADERS_ALL
WHERE QUOTE_VENDOR_QUOTE_NUMBER='foo.bar';
..reversing the order of MAX and NVL makes all the difference. This query returns the NULL value condition:
SELECT NVL(MAX(QUOTE_VENDOR_QUOTE_NUMBER),0)
FROM PO_HEADERS_ALL
WHERE QUOTE_VENDOR_QUOTE_NUMBER='foo.bar';

How to do a COUNT with a WHERE clause?

I actually have a query joining 3 tables to collect informations so I can calculate some KPIs, but my logic is flawed, here is my actual query :
SELECT t.idCustomer, t.nameCustomer
COUNT(DISTINCT t.idTrip),
SUM(
CASE
WHEN t.tripDone <> 1
THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.codeIncident = 'CANCEL'
THEN 1
ELSE 0
END)
FROM
(SELECT customer.idCustomer, customer.nameCustomer, trip.tripDone, incident.codeIncident
FROM CUSTOMER customer
JOIN TRIP trip ON customer.idCustomer = trip.idCustomer
JOIN INCIDENT incident ON trip.idTrip = incident.idTrip) t
GROUP BY t.idCustomer, t.nameCustomer
So, I want to know for each Customer :
COUNT(DISTINCT t.idTrip) -> The number of trips by this customer
Sum when t.tripDone <> 1 -> The number of trips that are done by this customer ( not ingoing )
Sum when t.codeIncident = 'CANCEL' -> The number of trips by this customer where there was a cancellation.
The big mistake I made here, is that a trip can have multiple codeIncidents (example : one record for an idTrip with the codeIncident 'CANCEL' and another record with same idTrip with the codeIncident 'DELAYED'), so when I calculate the Sum when t.tripDone <> 1 I get a result of : '2' instead of '1' (because there are 2 records in my from Clause that have the t.tripDone <> 1 for the same idTrip).
Would you have any idea on how I should process this query so I can do the Sum when tripDone <> 1 only once for each tripId ?
Thanks a lot for the help !
If you need some more infos I'm available, and sorry for my lack of english skills !
It sounds like you want to do the same count(distinct ...) pattern for the columns you're currently summing, but with some logic. You can use case within a count instead in the same way:
...
COUNT(
DISTINCT CASE
WHEN t.tripDone <> 1
THEN t.idTrip
ELSE null
END),
COUNT(
DISTINCT CASE
WHEN t.codeIncident = 'CANCEL'
THEN t.idTrip
ELSE null
END)
The else null is a bit redundant as that's the default. As count() ignores nulls, if the when isn't matched then that trip ID isn't counted.
First Select idTrip field in your inner query that means table "t"

SQL query and joins

Please see my query below:
select I.OID_CUSTOMER_DIM, I.segment as PISTACHIO_SEGMENT,
MAX(CASE WHEN S.SUBSCRIPTION_TYPE = '5' THEN 'Y' ELSE 'N' END ) PB_SUBS,
max(case when S.SUBSCRIPTION_TYPE ='12' then 'Y' else 'N' end) DAILY_TASTE,
MAX(CASE WHEN S.SUBSCRIPTION_TYPE ='8' THEN 'Y' ELSE 'N' END) COOKING_FOR_TWO
FROM WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID
WHERE S.SITE_CODE ='PB'and S.SUBSCRIPTION_END_DATE is null
group by I.oid_customer_dim, I.segment
In this one I am getting 654105 rows, which is lower than the one of the joins table with_mail_id which has 706795 rows.
Now, for the qc purpose my manager is wondering as why I am not having all the rows in my final table. I tried to remove all the filters but the results are still not same in both tables. What am I doing wrong?
I am not very good in SQL yet and this thing is really confusing me.
You're doing an inner join on the two tables, so only rows from WITH_MAIL_ID that can join against CUSTOMER_SUBSCRIPTION_FCT will be returned. Additionally you have a group clause.
First the join. If you want to return all rows regardless of the join condition, you can use a left join, but in this case all the S. columns will be NULL, and you'll have to deal with that.
If you run this, you might see the count is the difference:
select count(*) from WITH_MAIL_ID i
left join CUSTOMER_SUBSCRIPTION_FCT S
on I.IDENTITY_ID = S.IDENTITY_ID
where s.IDENTITY_ID is NULL
The most likely thing however is that it's just the grouping. If you are grouping on two columns and selecting the max of various other columns based on that grouping, you would expect that the number of rows returned is less than the original table, otherwise why bother grouping?
If I have data like this:
groupkey1 value
1 2
1 10
2 1
2 1
Then I group by groupkey1, and select MAX(value) I would get 2 rows [1,2], [2,1], not 4 rows.

Replacing In clause with exists

HI Gurus,
I'm looking to replace an IN clause with exists, but despite reading other similar cases on here I've not been able to apply them to my dataset.
I am looking to add in a column to my main query which tells me if a fund is found within a separate list, and if it does then label it 'emergency' and if not then 'non-emergency'
The list is defined like so:
select
f.id
FROM _audit a
INNER JOIN _fund f ON a.article_id = f.id
WHERE a.entity_name = 'Fund'
AND a.Changes LIKE
'%finance_code2%OldValue>3%'
)
UNION
(
select
id AS fund_reference
FROM _fund
WHERE (finance_code2 LIKE '3%'
OR finance_code2 LIKE '9%')
AND finance_code2 IS NOT NULL
And so what I am looking for is essentially something like:
SELECT
...Main query here...
,CASE WHEN fund_id IN (list_details) THEN 'emergency' else 'non-emergency' end
I know that it would be more efficient to do something like
SELECT
...Main query here...
,SELECT CASE WHEN EXISTS
(SELECT fund_id FROM list_details WHERE fund_id IS NOT NULL) THEN 'emergency' else 'non-emergency' END
But every time I try it keeps returning false values (saying that funds are contained within the list when they are not)
In case it helps I'm using sql server 2005 and the main query is listed below, where the list_details result (id) is joined onto donation_fund_allocation on list_details.id = donation_fund_allocation.fund_id
As always any clue would be massively appreciated :)
Thanks!
Main query
SELECT
don.supporter_id AS contact_id
,don.id AS gift_id
,YEAR(don.date_received) AS calendar_year
,YEAR(don.date_received) - CASE WHEN MONTH(don.date_received) < 4 THEN 1 ELSE 0 END AS financial_year
,don.date_received AS date_received
,don.event_id AS event_id
,SUM(CASE WHEN don.gift_aid_status <> 4 THEN don.value_gross * ((dfa.percentage) / 100)
WHEN don.gift_aid_status = 4 AND don.value_net > don.value_gross
AND don.value_net <> 0 THEN don.value_net * ((dfa.percentage) / 100)
ELSE don.value_gross * ((dfa.percentage) / 100)
END
) AS donation_value
--**List details query to go in here**
FROM donation don WITH (nolock)
INNER JOIN donation_fund_allocation dfa WITH (nolock) ON dfa.donation_id = don.id
WHERE don.supporter_id IS NOT NULL
AND don.status = 4
AND don.value_gross <> 0
GROUP BY don.supporter_id
,don.id
,don.date_received
,don.event_id
You need to correlate the exists call with the outer query. As written you are just asking if there exist any rows in list_details where fund_id isn't null
So, what you actually want is
SELECT
...Main query here...
,SELECT CASE WHEN EXISTS
(SELECT 1 FROM list_details WHERE fund_id = outer.fund_id) THEN 'emergency' else 'non-emergency' END
Where outer is the table alias for where fund_id can be found in your main select
You could write a function which takes the fund_id and returns an appropriate string value of "emergency" or "non-emergency".