SQL Select Distinct based on Conditional - sql

Assumptions:
ITEM STATUS in STAGINGLINE: 0 - NOT STARTED, 1 - VERIFIED, 2 - MISCOUNT
Want only one line to show per ASN so easiest way is using DISTINCT....
SELECT DISTINCT ASN, STATUS
FROM STAGINGLINE
However, I can't use a simple distinct because of the multiple STATUS possibilities, you would get multiples for each status.
Result set should show only 2 “ASNs”: 123 and 343
Example STAGINGLINE Table
Case 1:
(ASN #, ITEM #, STATUS, QTY ,ACTUAL)
123 898 0 4 NULL
123 344 0 9 NULL
123 123 0 2 NULL
123 534 0 1 NULL
343 111 1 6 6
ResultSet needs to be:
123 NOT STARTED (because all 0)
343 VERIFIED
Case 2:
(ASN #, ITEM #, STATUS, QTY ,ACTUAL)
123 898 1 4 4
123 344 0 9 NULL
123 123 0 2 NULL
123 534 0 1 NULL
ResultSet needs to be:
123 IN PROGRESS (because at least one of them is not in a 0 STATUS)
343 VERIFIED
Case 3:
(ASN #, ITEM #, STATUS, QTY ,ACTUAL)
123 898 1 4 4
123 344 2 9 5 <- MISCOUNT
123 123 0 2 NULL
123 534 0 1 NULL
ResultSet needs to be:
123 MISCOUNT (because of the existence of a 2 in at least one of the STATUS column)
343 VERIFIED
Case 4:
(ASN #, ITEM #, STATUS, QTY ,ACTUAL)
123 898 1 4 4
123 344 1 9 9
123 123 1 2 2
123 534 1 1 1
ResultSet needs to be:
123 VERIFIED (because all are STATUS of 1)
343 VERIFIED

Are you looking for max():
select asn, max(status)
from t
group by asn;
Or perhaps max() with case:
select (case max(status) when 0 then 'NOT STARTED'
when 1 then 'VERIFIED'
when 2 then 'MISCOUNT'
end)
from t
group by asn;
EDIT:
The rules seem a bit more detailed:
select (case when max(status) = 0 then 'NOT STARTED'
when max(status) = 1 and min(status) = max(status) then 'VERIFIED'
when max(status) = 2 then 'MISCOUNT'
else 'IN PROGRESS'
end)
from t
group by asn;

Can you try this,
SELECT ASN,
CASE WHEN MAX_STATUS = 2 THEN 'MISCOUNT'
WHEN MAX_STATUS = 0 THEN 'NOT STARTED'
WHEN MAX_STATUS = 1 AND MIN_STATUS = 1 THEN 'VERIFIED'
WHEN MAX_STATUS = 1 AND MIN_STATUS = 0 THEN 'IN-PROGRESS'
END STATUS
FROM
(SELECT ASN, MAX(STATUS) MAX_STATUS, MIN(STATS) MIN_STATUS
FROM STAGELINE
GROUP BY ASN) A

Related

Group by one column and return several columns on multiple conditions - T-SQL

I have two tables which I can generate with SELECT statements (joining multiple tables) as follows:
Table 1:
ID
Site
type
time
1
Dallas
2
01-01-2021
2
Denver
1
02-01-2021
3
Chicago
1
03-01-2021
4
Chicago
2
29-11-2020
5
Denver
1
28-02-2020
6
Toronto
2
11-05-2019
Table 2:
ID
Site
collected
deposited
1
Denver
NULL
29-01-2021
2
Denver
01-04-2021
29-01-2021
3
Chicago
NULL
19-01-2020
4
Dallas
NULL
29-01-2019
5
Winnipeg
13-02-2021
17-01-2021
6
Toronto
14-02-2020
29-01-2020
I would like the result to be grouped by Site, having on each column the COUNT of type=1 , type=2, deposited and collected, all of the 4 columns between a selected time interval. Example: (interval between 01-06-2020 and 01-06-2021:
Site
type1
type2
deposited
collected
Dallas
0
1
0
0
Denver
1
0
2
1
Chicago
1
1
0
0
Toronto
0
0
0
0
Winnipeg
0
0
1
1
How about union all and aggregation?
select site,
sum(case when type = 1 then 1 else 0 end) as type_1,
sum(case when type = 2 then 1 else 0 end) as type_2,
sum(deposited) as deposited, sum(collected) as collected
from ((select site, type, 0 as deposited, 0 as collected
from table1
) union all
(select site, null,
(case when deposited is not null then 1 else 0 end),
(case when collected is not null then 1 else 0 end)
from table2
)
) t12
group by site;
Combine your tables 1 and 2 with a join on Site
Use COUNT(CASE WHEN type = 1 then 1 END) as type1 and a similar construct for type 2
Use COUNT(CASE WHEN somedate BETWEEN '2020-06-01' and '2021-06-01' then 1 END) as ... for your dates

Select Data as per the given output

Table 1:
ID
CALLID
CALLSTATUS
1
123
Generated
2
321
Not Generated
3
343
Generated
4
567
Not Generated
5
789
Generated
Table 2:
UID
ID
CALLID
GENERATEDATE
RESULT
11
1
123
2021/3/18
1
21
1
123
2021/4/20
1
31
1
123
2021/5/20
0
41
2
321
NULL
NULL
51
3
343
2021/4/21
1
61
4
567
NULL
NULL
71
5
789
2021/5/1
0
Output of Oracle should be like below table:
ID
CALLID
GENERATEDATE
CALLSTATUS
RESULT
1
123
2021/4/20
Generated
1
2
321
NULL
Not Generated
NULL
3
343
2021/4/21
Generated
1
4
567
NULL
Not Generated
NULL
5
789
2021/5/1
Generated
0
The output which I want should be like above table. For CALLID '123', as per table 2 last generated call is on '2021/5/20' but it's result is '0' which i don't want to select. It should select '2021/4/21' because it's result is '1'. But for CALLID '789', No RESULT is '1' so it should select Generated Date as '2021/5/1'.
You can use conditional aggregation along with NVL() function depending on the values for the result column such as
SELECT t1.id, MAX(t1.callid) AS callid,
NVL(MAX(CASE WHEN result = 1 THEN t2.generatedate END),
MAX(CASE WHEN NVL(result,0)!=1 THEN t2.generatedate END)) AS generateddate,
MAX(t1.callstatus) AS callstatus, MAX(result) AS result
FROM Table1 t1
JOIN Table2 t2
ON t2.id = t1.id
AND t2.callid = t1.callid
GROUP BY t1.id
ORDER BY t1.id
ID
CALLID
GENERATEDDATE
CALLSTATUS
RESULT
1
123
20/04/2021
Generated
1
2
321
Not Generated
3
343
21/04/2021
Generated
1
4
567
Not Generated
5
789
01/05/2021
Generated
0
Demo

SQL merge 3 tables

I have an sql query involving 2 tables and try to add a third one.
These are the tables
FreeBookPos
FreeBooK_ID
ArticleNr
Amount
FreeBook
ID
BookNr
Date
FreeFields
FreeFieldType
Value
SQLPrimeKey
The first two are linked this way
select FreeBookPos.ArticleNr, Format(FreeBooking.Date, 'yyyy_MM') as dt,
SUM(CASE WHEN FreeBook.BookNr = 0 THEN FreeBookPos.Amount ELSE 0 END) as TotalEntryAmount,
SUM(CASE WHEN FreeBook.BookNr = 1 THEN FreeBookPos.Amount ELSE 0 END) as TotalLeftAmount
From FreeBookPos
INNER JOIN FreeBook on FreeBookPos.FreeBook_ID = FreeBook.ID
group by FORMAT ( FreeBook.Date, 'yyyy_MM'), FreeBookPos.ArticleNr
order by dt, ArticleNr
Now I need to add the table 3. This table is linked via SQLPrimeKey to FeeBook table ID. I then need to have only the fields where FreeFields.Value 2 or 4 and FreeFields.FreeFieldType = 54.
I tried various options with join but never get the result. Would I need to first join table 2 and 3 and then with 1 in a separate step?
Table 1: FreeBookPos
FreeBook_ID ArticleNr Amount
1 145 12
2 145 6
3 143 4
4 145 1
5 145 42
Table 2: FreeBook
ID BookNr Date
1 1 2012-05-19
2 -1 2012-05-21
3 1 2012-05-22
4 -1 2012-05-24
5 -1 2012-06-25
Table 3: FreeFields
SQLPrimareyKey FreeFieldType Value
1 54 1
2 52 2
3 54 4
4 54 2
5 54 2
Result should be:
ArticleNr Dt TotalEntryAmount TotalLeftAmount
143 2012-05 4 0
145 2012-05 0 -1
145 2012-06 0 -42
Try the below -
select FreeBookPos.ArticleNr, Format(FreeBooking.Date, 'yyyy_MM') as dt,
SUM(CASE WHEN FreeBook.BookNr = 0 THEN FreeBookPos.Amount ELSE 0 END) as TotalEntryAmount,
SUM(CASE WHEN FreeBook.BookNr = 1 THEN FreeBookPos.Amount ELSE 0 END) as TotalLeftAmount
From FreeBookPos
INNER JOIN FreeBook on FreeBookPos.FreeBook_ID = FreeBook.ID
inner join FreeFields on FreeBook.ID=SQLPrimareyKey
where value in (2,4) and FreeFieldType = 54
group by FORMAT ( FreeBook.Date, 'yyyy_MM'), FreeBookPos.ArticleNr
order by dt, ArticleNr

Find count of transactions and customer where they have purchased one item along with something else SQL

I have a table which has the transaction details of the customer:
Customernum sls unit txn no SKU txn_date
1 10 30 567 903633 2019-02-01 yes
1 20 30 567 123767 2019-02-01 yes
1 50 40 567 126658 2019-03-01 yes
1 10 40 345 773633 2019-02-10 yes
1 12 30 345 965322 2019-02-10
1 10 50 678 838364 2019-02-15 yes
1 10 70 975 983636 2019-02-28 yes
2 11 80 910 903633 2019-02-11
2 11 90 910 566373 2019-02-12 yes
3 11 62 855 678364 2019-02-12
I have another table which has the SKU:
sku Desc
123767 APP
903633 CD
773633 APP
838364 APP
983636 APP
566373 APP
126658 APP
I need to find the transactions from the above transactions which has 903633 in the transaction along with the other SKU from the SKU table and transactions which have more than one of the SKU' from the above table.
So the two questions I am trying to anwer is :
How many transactions included only 1 apparel item along with CD
How many transactions included more than one apparel items with CD.
I have tried the below query but I have had no luck:
select a.Customernum, a.txnno, td.sku,
case when ps.sku is not null
then 'Yes'
else 'No'
end as is_sku,
case when count(b.sku) over (partition by a.txnno) > 0
then 'Yes'
else 'No'
end as has_sku
from table a
left join sku b on b.sku = a.sku;
I am expecting the below result:
Result 1- How many transactions included only 1 apparel item along with CD
customernum txnno unit sls
2 910 80 11
2 910 90 11
1 678 50 10
1 975 70 10
Result 2- How many transactions included more than one apparel items with CD.
customernum txnno unit sls
1 567 30 10
1 567 30 20
1 567 40 50
Use two levels of aggregation. The subquery counts the number of "app"s and "cd"s. The outer filter to just one "cd" (you can use >= if you want at least one) and aggregates by the number of "app"s:
select num_app, count(*) as num_customers
from (select t.customernum,
sum(case when s.desc = 'APP' then 1 else 0 end) as num_app,
sum(case when s.desc = 'CD' then 1 else 0 end) as num_cd
from transactions t join
skus s
on t.sku = s.sku
) c
where num_cd = 1
group by num_app
order by num_app;
You can filter with window functions.
The following query would give you all transactions that involve sku 903633 with exactly one other sku:
select *
from (
select
t.*,
count(*) over(partition by txnno) cnt,
max(case when sku = 903633 then 1 end) has_cd
from mytable t
) t
where has_cd = 1 and cnt = 2
To get the transactions that involve sku 903633 and at least two other skus, you can just change cnt = 2 to cnt > 2.

Multiple times Grouping with where in SQL Server

I have a source table like this
ProductName SaleReceipt SaleCode
--------------------------------
F-Apple 1001 1
F-Orange 1002 2
G-Rice 1003 3
G-Barile 1005 4
G-Oats 1006 1
V-Carrot 1007 4
V-Cabbage 1008 3
V-Potato 1009 1
V-Tomato 1010 1
Chocolate 1011 4
Cookies 1012 1
Cakes 1013 2
I need to create a report like this
30 Day delay 60 Day Delay 90 day delay 120 day delay
Fruits 1 1 0 0
Grains 1 0 1 1
Vegetables 2 0 1 1
Other category 1 1 0 1
The conditions to create the report are:
All ProductName start with F is grouped as fruits
All ProductName start with G is grouped as Grains
All ProductName start with V is grouped as Vegetables
Other product name go in the other category
30 day delay: count of (SaleReceipt) with a SaleCode=1
60 day delay: count of (SaleReceipt) with a SaleCode=2
90 day delay: count of (SaleReceipt) with a SaleCode=3
120 day delay: count of (SaleReceipt) with a SaleCode>=4
I could not find how to do grouping two times. I am using SQL Server 2014.
You can use case in a group by. Or use a lookup table:
select coalesce(c.name, 'Other category'),
sum(case when salescode = 1 then 1 else 0 end) as salecode_1,
sum(case when salescode = 2 then 1 else 0 end) as salecode_2,
sum(case when salescode = 3 then 1 else 0 end) as salecode_3,
sum(case when salescode = 4 then 1 else 0 end) as salecode_4
from t left join
(values ('F-%', 'Fruit'), ('G-%' , 'Grain'), ('V-%', 'Vegetable')
) c(pattern, name)
on t.productname like c.pattern
group by coalesce(c.name, 'Other category');