Subqueries in MSSQL producing NULL values - sql

I am trying to determine my store only accounts revenue from the database, to do this I need to look through all account numbers with revenue against a 'store' description who do NOT appear in a list of accounts with an 'online' description which I have tried todo in the subquery below. The query runs however it just returns NULL values in my store_only_revenue column. Any guidance on what to do from here would be appreciated. Am I approaching the problem in a good way? Or is there a better solution:
SELECT
town,
financial_pd as month,
SUM(CASE WHEN [Descr] = 'online' THEN Net_Revenue ELSE 0 END) as online_revenue,
SUM(CASE WHEN [Descr] = 'store' THEN Net_Revenue ELSE 0 END) as store_revenue,
COUNT(DISTINCT CASE WHEN [Descr] = 'online' THEN Account_Number ELSE NULL END) as online_accounts,
COUNT(DISTINCT CASE WHEN [Descr] = 'store' THEN Account_Number ELSE NULL END) as store_accounts,
(SELECT
SUM(Net_Revenue)
FROM [mydb].[dbo].[mytable]
WHERE
Descr = 'store'
AND Account_Number
NOT IN(
SELECT DISTINCT Account_Number
FROM [mydb].[dbo].[mytable]
WHERE
Descr = 'online')
) as store_only_revenue
FROM [mydb].[dbo].[mytable] as orders
WHERE
Group_name = 'T'
AND NOT
Type_name_1 = 'Electronic'
AND
Account_type <> 1
AND
Total_Value > 0
AND
(Insert_Date BETWEEN '2016-05-30' AND '2016-07-03'
OR
Insert_Date BETWEEN '2015-05-25' AND '2015-06-28')
OR
(Insert_Date BETWEEN '2016-05-30' AND '2016-07-03'
AND
Insert_Date BETWEEN '2015-05-25' AND '2015-06-28')
GROUP BY
town,
financial_pd as period

This expression is suspect:
Account_Number NOT IN (SELECT DISTINCT t.Account_Number
FROM [mydb].[dbo].mytable t
WHERE t.Descr = 'online'
)
Assuming that the syntax problems are typos (missing table name, desc is a reserved word), then this will never return true if even one Account_Number is NULL. One way to fix this is:
Account_Number NOT IN (SELECT t.Account_Number
FROM [mydb].[dbo].mytable t
WHERE t.Desc = 'online' AND t.Account_Number IS NOT NULL
)
I would use NOT EXISTS:
not exists (select 1
from [mydb].[dbo].??? x
where x.Desc = 'online' AND ??.Account_Number = x.Account_Number
)
You need to use proper table aliases for this to work. Either of these solutions may fix your problem.

Related

How to get the value as per type from one column and display it as multiple column in hive?

The below query will populate only check no and ac no even if there is data in rest of the column. How to populate all column from the value?
query:
select distinct * from(
select
(CASE WHEN b.dtl_typ = 'CheckNumber' THEN b.col_val END) as `Check Number`,
a.acc_id as Account_Number,
(CASE WHEN b.dtl_typ = 'AddressLine1' THEN b.col_val END) as `Address Line 1`,
(CASE WHEN b.dtl_typ = 'AddressLine2' THEN b.col_val END) as `Address Line 2`,
(CASE WHEN b.dtl_typ = 'City' THEN b.col_val END) as City,
(CASE WHEN b.dtl_typ = 'State' THEN b.col_val END) as State,
(CASE WHEN b.dtl_typ = 'Zipcode' THEN b.col_val END) as ZipCode
from
(select *from(select acc_id as acc_id, row_number() over(partition by acc_id order by booking_ts desc) rw_nbr
from TABLE1 where P_CODE = 'CheckTrnsfr' ) d where rw_nbr = 1) a
LEFT OUTER JOIN
(select acc_id, dtl_val as col_val, dtl_typ
from TABLE2 where dtl_typ in('AddressLine1','AddressLine2','City','State','Zipcode','CheckNumber')) b on b.acc_id = a.acc_id)a where
`Check Number` is not null
output:
expected output:The above picture only populate check no and a/c no and rest of the column is null even if the data is present which should not be happen. All column should populate with the available data.It is possible if i use more then one left join with where clause one by one like: dtl_typ= 'AddressLine1' left join dtl_typ='AddressLine2 and so on, but that should be a performance issue. It will hit DB multiple times.
select acc_id, dtl_val as col_val, dtl_typ from TABLE2 where dtl_typ in('AddressLine1','AddressLine2','City','State','Zipcode')
output:

Roll up multiple rows into one

I have a table that looks like this:
USER_ID,ADDED_DATE,STATUS,COMPLETION_ID_TYPE,QA_OPTION,QA_OPTION_COUNT
12543,2020-06-01 00:00:00,qaComplete_L2,chart,Correct,3
12543,2020-06-01 00:00:00,qaComplete_L2,chart,Incorrect,3
12543,2020-06-12 00:00:00,qaComplete_L2,chart,Incorrect,1
12543,2020-06-12 00:00:00,qaComplete_L2,chart,Correct,1
I want to display the results as:
USER_ID ADDED_DATE STATUS COMPLETION_ID_TYPE L2 Correct L2 InCorrect
8388 6/01/20 0:00 qaComplete_L2 chart 3 3
8388 6/12/20 0:00 qaComplete_L2 chart 1 1
I have tried this but not getting the results I am expecting:
select distinct user_id,
added_date,
status,
completion_id_type,
max(case
when qa_option = 'Correct'
then qa_option_count
else 0
end) as L2_Correct,
max(case
when qa_option = 'Incorrect'
then qa_option_count
else 0
end) as L2_Incorrect
from qa_report2
where user_id = 12543
and status = 'qaComplete_L2'
group by user_id, status, added_date, completion_id_type,qa_option, qa_option_count
order by user_id, added_date;
;
USER_ID,ADDED_DATE,STATUS,COMPLETION_ID_TYPE,L2_CORRECT,L2_INCORRECT
12543,2020-06-01 00:00:00,qaComplete_L2,chart,0,3
12543,2020-06-01 00:00:00,qaComplete_L2,chart,3,0
12543,2020-06-12 00:00:00,qaComplete_L2,chart,1,0
12543,2020-06-12 00:00:00,qaComplete_L2,chart,0,1
You were almost there :)
I only removed the distinct and two last group by columns. Columns you need in the calculation, shouldn't appear in the group by clause, but only in the group function in the select clause.
So in the end, what I think you're looking for is:
select user_id,
added_date,
status,
completion_id_type,
max(case
when qa_option = 'Correct'
then qa_option_count
else 0
end) as L2_Correct,
max(case
when qa_option = 'Incorrect'
then qa_option_count
else 0
end) as L2_Incorrect
from qa_report2
where user_id = 12543
and status = 'qaComplete_L2'
group by user_id,
status,
added_date,
completion_id_type
--,qa_option
--,qa_option_count
order by user_id,
added_date;
Note: You should be aware that you're using max(), I can imagine that if multiple records exist, you actualy want to use sum(), but that really depends on your use case.
You can use the PIVOT to achieve it.
SELECT *
FROM (
SELECT USER_ID,
ADDED_DATE,
STATUS,
COMPLETION_ID_TYPE,
QA_OPTION_COUNT,
QA_OPTION
FROM QA_REPORT2
WHERE USER_ID = 12543
AND STATUS = 'qaComplete_L2'
) PIVOT (
MAX ( QA_OPTION_COUNT )
FOR QA_OPTION
IN ( 'Correct' AS L2_CORRECT, 'Incorrect' AS L2_INCORRECT )
);

How to count multiple columns in SQL (Oracle) with criteria?

I'm working on SMS-Gateway that holds multiple charged SMS-services with different numbers,
each SMS sent to the customer has 4 status as below (forwarded, delivered, expired,delivery failed)
Now I have the below first_table for the charging-system with the below details (TABLE-A)
and below (TABLE-B) which contain the status of each sent SMS with its ID
Below is my expected final result to forecast the details for each sms-service :
At first I thought it was easy all I need is just to use COUNT(Case when ...)
but in my case I have thousands of SMS-numbers(services) so if I use this approach it will be like that:-
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='forwarded' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='delivered' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='expired' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='delivery failed' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='forwarded' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='delivered' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='expired' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='delivery failed' )
...
...
...
...
...
...
...
The above approach not practical when you have many services also noting that CASE can handle only 250 conditions?
So what is the best approach to do left outer join for (Table A) on (Table B) using the SMS-ID and count each SMS-status and forecast it as below?
I would suggest conditional aggregation:
select b.SMS_SHORT_CODE,
sum(case when status = 'forwaded' then 1 else 0 end) as count_of_forwaded,
sum(case when status = 'delivered' then 1 else 0 end) as count_of_status,
sum(case when status = 'expired' then 1 else 0 end) as count_of_expired,
sum(case when status = 'delivery failed' then 1 else 0 end) as count_of_delivery_failed
from TABLEB b
group by b.SMS_SHORT_CODE ;
Note that no JOIN is necessary. All the data you want to aggregate is in TABLEB.
Please use below query,
select
A.SMS_SHORT_CODE,
case when status = 'forwaded' then count(status ) end as count_of_forwaded,
case when status = 'delivered' then count(status ) end as count_of_status,
case when status = 'expired' then count(status ) end as count_of_expired,
case when status = 'delivery failed' then count(status ) end as count_of_delivery_failed
from TABLEA A
inner join TABLEB B
on (A.SMS_ID = B.SMS_ID)
group by A.SMS_SHORT_CODE, status ;
You can use PIVOT clause (introduced in Oracle 11g version) for those status columns :
SELECT sms_short_code,
COUNT_OF_forwarded,
COUNT_OF_delivered,
COUNT_OF_expired,
COUNT_OF_delivery_failed
FROM tableB
PIVOT
(
COUNT(*) FOR status IN ( 'forwarded' AS COUNT_OF_forwarded,
'delivered' AS COUNT_OF_delivered,
'expired' AS COUNT_OF_expired,
'delivery failed' AS COUNT_OF_delivery_failed )
)
e.g. only using TableB is enough.
Demo

SQL Aggreate Functions

I have table which list a number of cases and assigned primary and secondary technicians. What I am trying to accomplish is to aggregate the number of cases a technician has worked as a primary and secondary tech. Should look something like this...
Technician Primary Secondary
John 4 3
Stacy 3 1
Michael 5 3
The table that I am pulling that data from looks like this:
CaseID, PrimaryTech, SecondaryTech, DOS
In the past I have used something like this, but now my superiors are asking for the number of secondary cases as well...
SELECT PrimaryTech, COUNT(CaseID) as Total
GROUP BY PrimaryTech
I've done a bit of searching, but cant seem to find the answer to my problem.
Select Tech,
sum(case when IsPrimary = 1 then 1 else 0 end) as PrimaryCount,
sum(case when IsPrimary = 0 then 1 else 0 end) as SecondaryCount
from
(
SELECT SecondaryTech as Tech, 0 as IsPrimary
FROM your_table
union all
SELECT PrimaryTech as Tech, 1 as IsPrimary
FROM your_table
) x
GROUP BY Tech
You can group two subqueries together with a FULL JOIN as demonstrated in this SQLFiddle.
SELECT Technician = COALESCE(pri.Technician, sec.Technician)
, PrimaryTech
, SecondaryTech
FROM
(SELECT Technician = PrimaryTech
, PrimaryTech = COUNT(*)
FROM Cases
WHERE PrimaryTech IS NOT NULL
GROUP BY PrimaryTech) pri
FULL JOIN
(SELECT Technician = SecondaryTech
, SecondaryTech = COUNT(*)
FROM Cases
WHERE SecondaryTech IS NOT NULL
GROUP BY SecondaryTech) sec
ON pri.Technician = sec.Technician
ORDER By Technician;
SELECT COALESCE(A.NAME, B.NAME) AS NAME, CASE WHEN A.CASES IS NOT NULL THEN A.CASES ELSE 0 END AS PRIMARY_CASES,
CASE WHEN B.CASES IS NOT NULL THEN B.CASES ELSE 0 END AS SECONDARY_CASES
FROM
(
SELECT COUNT(*) AS CASES, PRIMARYTECH AS NAME FROM YOUR_TABLE
GROUP BY PRIMARYTECH
) AS A
FULL OUTER JOIN
(
SELECT COUNT(*) AS CASES, SECONDARYTECH AS NAME FROM YOUR_TABLE
GROUP BY SECONDARYTECH
) AS B
ON A.NAME = B.NAME

SQL select display row data as columns for varchar items

This is the query I am using to generate my table:
SELECT cu.idchanneluser AS Approver,
mcr.idrule AS Rule,
mrd.idseq AS Seq,
mcr.idcust AS CustID,
cu.iduser AS USERID
FROM mstchanneluser cu,
mstcatruledetail mrd,
mstcatrule mcr
WHERE idchannel='01'
AND mrd.idlist=cu.iduser
AND mrd.idrule=mcr.idrule
AND mcr.nbrauth='2'
AND mcr.isautoauth='N'
and this the snapshot of result:
but I want result like this:
FirstAuthorizer SecondAuthorzier Rule
rohitcorp ajitcorp 3090
CORPTEST TESTCORP 8634
ABHIMAKER CORPTEST 11705
I tried this query:
SELECT CASE WHEN idseq = '0' THEN idchanneluser ELSE NULL END AS Approver,
case when idseq = '1' THEN idchanneluser ELSE NULL END AS secondApprover,
cu.idchanneluser AS Approver,
mcr.idrule AS Rule,
mrd.idseq AS Seq,
mcr.idcust AS CustID,
cu.iduser AS USERID
FROM mstchanneluser cu,
mstcatruledetail mrd,
mstcatrule mcr
WHERE idchannel='01'
AND mrd.idlist=cu.iduser
AND mrd.idrule=mcr.idrule
AND mcr.nbrauth='2'
AND mcr.isautoauth='N'
and it will be returning me this result check the snapshot.
this is derived from your second query, you just need to use MAX and group them by mcr.idrule
SELECT MAX(CASE WHEN idseq = '0' THEN idchanneluser ELSE NULL END) AS Approver
, MAX(CASE WHEN idseq = '1' THEN idchanneluser ELSE NULL END) AS secondApprover
, mcr.idrule AS RULE
FROM mstchanneluser cu
, mstcatruledetail mrd
, mstcatrule mcr
WHERE idchannel = '01'
AND mrd.idlist = cu.iduser
AND mrd.idrule = mcr.idrule
AND mcr.nbrauth = '2'
AND mcr.isautoauth = 'N'
GROUP BY mcr.idrule
Another way in oracle with Analytical function lead lag
select tab.y FirstAuthorizer,tab.x SecondAuthorzier,tab.rule from
(
select lead(appprover,0) over (partition by rule order by seq) x ,
lag(appprover,1) over (partition by rule order by seq) y,
rule
from tbl ) tab
where tab.y is not null;