Expression within case statement using two tables - sql

I need help with the last column/case statement that I'm trying to add to my query. The last column is called atleast_1_stored. This column will identify whether or not any item within the shipment was stored. If so, "yes" if none then no.
There are 4 calculated columns in this query.
1st new column = Shipment_Size (# of itemsID in that shipment)
2nd new column = Shipment_ready (entire shipmentID is ready to be shipped. For an shipmentID to be ready to be shipped all the ItemIDs must be in a "Packed" status)
3rd new column = Item_Stored (was this item stored atleast 1 time). If it was stored atleast 1 time value should be yes and if the item was never stored atleast 1 time the value should be no.
4th new column = This column will identify whether or not any item within the shipmentID was stored. If so, "yes" for all shipmentID associated with that orderID.
DROP TABLE Shipment_Info;
DROP TABLE Item_Info;
CREATE TABLE Shipment_Info (
ShipmentID int,
ItemID int,
Item_status varchar(255) );
CREATE TABLE Item_info (
ItemID int,
Item_Status varchar(255) );
INSERT INTO Shipment_Info (
ShipmentID,
ItemID,
Item_status ) VALUES (10001,20001,'Packed'), (10002, 20002, 'Allocated'), (10002, 20003, 'Packed'), (10003, 20004, 'Filled'), (10004, 20005, 'Packed'), (10004, 20006, 'Packed'), (10004, 20007, 'Packed'), (10005, 20008, 'Filled'), (10005, 20009, 'Packed'), (10006, 20010, 'Filled');
INSERT INTO Item_Info (
ItemID,
Item_Status ) VALUES (20001, 'Induct'), (20001, 'Stock'), (20002, 'Induct'), (20002, 'Stock'), (20002, 'Stored'), (20002, 'Dock'), (20003, 'Induct'), (20003, 'Stock'), (20003, 'Stored'), (20004, 'Induct'), (20004, 'Cancelled'), (20004, 'Stored'), (20005, 'Induct'), (20005, 'Stock'), (20005, 'Stored'), (20006, 'Induct'), (20006, 'Reject'), (20006, 'Induct'), (20006, 'Stock'), (20007, 'Induct'), (20007, 'Stock'), (20007, 'Stored'), (20007, 'Stored'), (20008, 'Induct'), (20008, 'Stock'), (20008, 'Reject'), (20009, 'Induct'), (20009, 'Stock'), (20009, 'Induct'), (20009, 'Stored'), (20010, 'Induct'), (20010, 'Stock');
Ideal Output:
ShipmentID
ItemID
Shipment_Size
Shipment_Ready
Item_Stored
Atleast_1_Stored
10001
20001
1
Yes
No
No
10002
20002
2
No
Yes
Yes
10002
20003
2
No
Yes
Yes
10003
20004
1
No
Yes
Yes
10004
20005
3
Yes
Yes
Yes
10004
20006
3
Yes
No
Yes
10004
20007
3
Yes
Yes
Yes
10005
20008
2
No
No
Yes
10005
20009
2
No
Yes
Yes
10006
20010
1
No
Yes
Yes
select ShipmentID, ItemID
, count(ItemID) over (partition by ShipmentID) Shipment_Size
, case when
sum(case when Item_status='Packed' then 1 else 0 end) over (partition by ShipmentID ) = count(ItemID) over (partition by ShipmentID)
then 'Yes' else 'No' end as Shipment_Ready
, case when exists (select 1 from Item_Info ii where ii.ItemId = si.ItemId and ii.Item_Status = 'Stored') then 'Yes' else 'No' end as Item_Stored
--Case Statement I need help with
case when sum(exists(select 1 from Item_Info ii where ii.ItemId = si.ItemId and ii.Item_Status = 'Stored')) over (partition by ShipmentID) != 0 then 'Yes' else 'No' end as Atleast_1_stored
--End Case statement i need help with
from Shipment_INFO si
group by ShipmentID, Item_status, ItemID;

select ShipmentID, ItemID
, count(ItemID) over (partition by ShipmentID) Shipment_Size
, case when
sum(case when Item_status='Packed' then 1 else 0 end) over (partition by ShipmentID ) = count(ItemID) over (partition by ShipmentID)
then 'Yes' else 'No' end as Shipment_Ready,
case when exists (select 1 from Item_Info ii where ii.ItemId = si.ItemId and ii.Item_Status = 'Stored') then 'Yes' else 'No' end as Item_Stored,
case when
sum(
(select count(case when Item_Status = 'Stored' then Item_Status else null end ) from Item_Info where Item_Info.ItemID = si.ItemID))
over (partition by ShipmentID ) > 0 then 'Yes' else 'No' end as Atleast_1_stored
from Shipment_INFO si
demo : https://dbfiddle.uk/OC1GP79a

SELECT
si.shipmentid,
si.itemid,
count(*) OVER(PARTITION BY si.shipmentid) shipment_size,
CASE WHEN SUM(CASE WHEN item_status='Packed' THEN 1 ELSE 0 END) OVER (partition by si.shipmentid)=COUNT(si.itemid) OVER (PARTITION BY si.shipmentid) THEN 'Yes' ELSE 'No' END AS shipment_ready,
CASE WHEN stored.itemid IS NOT NULL THEN 'Yes' Else 'No'END AS item_stored,
CASE WHEN at_least_1_stored.shipmentid IS NOT NULL THEN 'Yes' ELSE 'No' END AS at_least_1_stored
FROM
shipment_info si
LEFT JOIN
(
SELECT
DISTINCT itemid
FROM
item_info
WHERE
item_status='Stored'
)stored
ON
stored.itemid=si.itemid
LEFT JOIN
(
SELECT
shipmentid
FROM
shipment_info
INNER JOIN
(SELECT
DISTINCT itemid
FROM
item_info
WHERE
item_status='Stored')x
ON
x.itemid=shipment_info.itemid
)at_least_1_stored
ON
at_least_1_stored.shipmentid=si.shipmentid
FIDDLE : https://dbfiddle.uk/wRO1yHbr

Related

Comparing values in two columns and returning values on conditional bases using sql hive

I have two columns, I want to get an output based on a comparative basis of both. My data is somewhat like:
Customer Id status
100 A
100 B
101 B
102 A
103 A
103 B
So a customer can have a status A or B or both, I have to segrerate them on customer id basis for a status. If status A and B then return happy, if only A, return Avg and if only B return Sad.
try the below query,
SELECT DISTINCT Customer_Id,
(CASE WHEN COUNT(*) OVER(PARTITION BY Customer_Id) > 1 THEN 'happy'
WHEN Tstatus = 'A' THEN 'Avg'
ELSE 'Sad'END) AS New_Status
FROM #table1
GROUP BY Customer_Id,Tstatus
if Customer Id and status is a unique combination then
STEP 1: use case to determine a or b
SELECT customer id
,CASE WHEN avg(case when [status] ='A' then 0 else 2 end)
FROM [Your Table]
group by[customer id]
and step 2 will be casing avg into result: like this
SELECT customer id
,CASE WHEN (avg(case when [status] ='A' then 0 else 2 end)) = 1 THEN 'happy' ELSE WHEN (avg(case when [status] ='A' then 0 else 2 end)) = 0 THEN 'Avg' ELSE 'Sad' END
FROM [Your Table]
group by[customer id]
I would do this simply as:
select customer_id,
(case when min(status) <> max(status) then 'happy'
when min(status) = 'A' then 'avg'
else 'sad'
end)
from t
where status in ('A', 'B')
group by customer_id

SQL/HIVE - resolve issue (small change) - Partition

I have the below code, which mostly works correctly with some other scenarios I tested.
However, for the example below I am trying to count the number for N-CO (non completions) until completion but it return 5 instead of 3.
And i am trying to create another column to count the PARTIALLY which is 2.
Any once have some input as to why?
What do I need to change?
CREATE TABLE #temp
(
Identifier varchar(20)NOT NULL
,CreatedDate DATETIME NOT NULL
,CompletedDate DATETIME NOT NULL
,SN_Type varchar(20) NOT NULL
,SN_Status varchar(20) NOT NULL
)
;
INSERT INTO #temp
VALUES('64074558792','20160729','20160805','Re-Activattion','N-CO');
INSERT INTO #temp
VALUES('64074558792','20160729','20160805','Re-Activattion','PARTIALLY');
INSERT INTO #temp
VALUES('64074558792','20160809','20160809','Re-Activattion','PARTIALLY');
INSERT INTO #temp
VALUES('64074558792','20160810','20160810','Re-Activattion','N-CO');
INSERT INTO #temp
VALUES('64074558792','20160812','20160812','Re-Activattion','N-CO');
INSERT INTO #temp
VALUES('64074558792','20160811','20160811','Re-Activattion','COMP');
INSERT INTO #temp
VALUES('64074558792','20160811','20160813','Re-Activattion','N-CO');
;
WITH Src AS (
SELECT Identifier, CreatedDate, CompletedDate, SN_Type, SN_Status,
ROW_NUMBER() OVER(PARTITION BY Identifier ORDER BY CreatedDate, CASE WHEN SN_Status = 'COMP' THEN 1 ELSE 0 END, CompletedDate) AS rn,
ROW_NUMBER() OVER(PARTITION BY Identifier ORDER BY CreatedDate, CASE WHEN SN_Status = 'COMP' THEN 1 ELSE 0 END, CompletedDate) -
ROW_NUMBER() OVER(PARTITION BY Identifier,CASE WHEN SN_Status = 'COMP' THEN 1 ELSE 0 END ORDER BY CreatedDate, CompletedDate) AS grp
FROM #temp
),
Grouped AS (
SELECT Identifier, CASE WHEN SN_Status = 'COMP' THEN 1 ELSE 0 END AS IsCOMP,
MIN(CreatedDate) AS StartDate,
COUNT(*) AS [RE-AN NCO #],
MAX(rn) AS LastRn
FROM Src
GROUP BY Identifier, CASE WHEN SN_Status = 'COMP' THEN 1 ELSE 0 END, grp
),
grouped2 AS (SELECT Identifier, MAX(rn) AS maxRN
FROM [Src]
GROUP BY [Src].[Identifier])
SELECT s.Identifier,
CASE WHEN isComp = 0
THEN
CAST(DATEDIFF(day,g.StartDate,s.CreatedDate) AS VARCHAR(25))
ELSE
'NOT COMPLETED'
END AS RE_ACT_COMPLETION_TIME,
g.[RE-AN NCO #]
FROM Src s
INNER JOIN Grouped g ON g.Identifier = s.Identifier
AND g.LastRn + 1 = s.rn
JOIN grouped2 g2 ON [g2].[Identifier] = [s].[Identifier]
WHERE s.SN_Status = 'COMP'
OR (SN_Status <> 'COMP' AND maxRN = [s].[rn])
ORDER BY rn;
DROP TABLE #temp
select Identifier
,COMP_id
,count(case when SN_Status = 'N-CO' then 1 end) as count_N_CO
,count(case when SN_Status = 'PARTIALLY' then 1 end) as count_PARTIALLY
,count(case when SN_Status = 'COMP' then 1 end) as is_COMP
from (select Identifier
,SN_Status
,count(case when SN_Status = 'COMP' then 1 end) over
(
partition by Identifier
order by CreatedDate, case when SN_Status = 'COMP' then 1 else 0 end, CompletedDate
rows between unbounded preceding and 1 preceding
) + 1 as COMP_id
from #temp
) t
group by Identifier
,COMP_id
+-------------+---------+------------+-----------------+---------+
| Identifier | COMP_id | count_N_CO | count_PARTIALLY | is_COMP |
+-------------+---------+------------+-----------------+---------+
| 64074558792 | 1 | 3 | 2 | 1 |
| 64074558792 | 2 | 1 | 0 | 0 |
+-------------+---------+------------+-----------------+---------+

Combine multiple rows into 1 row

Say for example I have a table that contains a description of a customer's activities while in a cafe. (Metaphor of the actual table I am working on)
Customer Borrowed Book Ordered Drink Has Company
1 1
1 1
1 Yes
2 1
3 1
3 Yes
4 1 1
4 1
I wish to combine the rows in this way
Customer Borrowed Book Ordered Drink Has Company
1 1 1 Yes
2 1
3 1 Yes
4 1 2
I did self join with coalesce, but it did not give my desired results.
You can do this by group by,
select Customer,sum([borrowed book]), sum([ordered drink]), max([has company])
from customeractivity group by Customer
As per your comment, initial table is a temp table,
Try to make the result as a cte result, then do aggregation on that, like the below query.
; WITH cte_1
AS
( //your query to return the result set)
SELECT customer,sum([borrowed book]) BorrowedBook,
sum([ordered drink]) OrderedDrink,
max([has company]) HasCompany
FROM cte_1
GROUP BY Customer
Use Group By:
DECLARE #tblTest as Table(
Customer INT,
BorrowedBook INT,
OrderedDrink INT,
HasCompany BIt
)
INSERT INTO #tblTest VALUES
(1,1,NULL,NULL)
,(1,NULL,1,NULL)
,(1,NULL,NULL,1)
,(2,NULL,1,NULL)
,(3,NULL,1,NULL)
,(3,NULL,NULL,1)
,(4,1,1,NULL)
,(4,NULL,1,NULL)
SELECT
Customer,
SUM(ISNULL(BorrowedBook,0)) AS BorrowedBook,
SUM(ISNULL(OrderedDrink,0)) AS OrderedDrink,
CASE MIN(CAST(HasCompany AS INT)) WHEN 1 THEN 'YES' ELSE '' END AS HasCompany
FROM #tblTest
GROUP BY Customer
Not sure, why you are getting error with group by.
Your coalesce should be correct. Refer below way.
Select customer
, case when [borrowed] = 0 then NULL else [borrowed] end as [borrowed]
, case when [ordered] = 0 then NULL else [ordered] end as [ordered]
, case when [company] = 1 then 'Yes' end as company
from
(
Select customer,
coalesce(
case when (case when borrowed = '' then null else borrowed end) = 1 then 'borrowed' end,
case when (case when ordered = '' then null else ordered end) = 1 then 'ordered' end,
case when (case when company = '' then null else company end) = 'Yes' then 'company' end
) val
from Table
) main
PIVOT
(
COUNT (val)
FOR val IN ( [borrowed], [ordered], [company] )
) piv
OUTPUT:
customer | borrowed | ordered | company
---------------------------------------
1 1 1 Yes
2 NULL 1 NULL
3 NULL 1 Yes

SQL: Add a column and classify into categories

I have a table which has transaction_id as the primary key and also contains customer_id which is a foreign key.
Now there is a column type which has two values: 'Card' and 'cash'.
Now some of the customers have used both the methods for payment. I want to add a new column and classify the customers as "Only card" "Only cash" and "Both".
Transaction id Customer id Type
1 100 Card
2 101 Cash
3 102 Card
4 103 Cash
5 101 Card
So in this table I want a new column 'Type of payment' which classifies customer 101 as Both since he has used both the methods of payment.
You can use window functions:
select t.*,
(case when min(type) over (partition by customerid) = max(type) over (partition by customerid)
then 'Only ' + min(type) over (partition by customerid)
else 'both'
end)
from transactions t;
You can do better and remove a bit of redondancy (the values cash only and card only will be repeated in the table, in this case we prefer repeating an ID). So you can create a Table for example payement_methods that will have 2 columns for example id and method, you will populate it with the three options you just mentioned (cash only, card only, both), and you'll have in your transaction table a column payment_method_id for example (instead of the type column you were using).
example
|id | method |
|1 | Cash only |
|2 | Card Only |
|3 | Both |
transaction table
|id | other columns ...|payement method |
|1 | other columns ...|1 |
|2 | other columns ...|3 |
//...
sorry for my english, good luck.
Rather than adding a column to the table, if what you want to do is analyze the payment methods, then doing something like this might be better:
SELECT DISTINCT Table1.[Customer ID], T1.*
FROM Table1
CROSS APPLY (SELECT SUM(CASE WHEN [Type] = 'Cash' THEN 1 ELSE 0 END) AS Cash,
SUM(CASE WHEN [Type] = 'Card' THEN 1 ELSE 0 END) AS Card
FROM Table1 T WHERE T.[Customer ID] = Table1.[Customer ID]) T1
Gives you results like this:
CUSTOMER ID CASH CARD
100 0 1
101 1 1
102 0 1
103 1 0
Create table tran1(Transactionid int , Customerid int , Type varchar(100))
insert into tran1(Transactionid , Customerid , Type ) values
(1 , 100 , 'Card ' ),
(2 , 101 , 'Cash' ),
(3 , 102 , 'Card ' ),
(4 , 103 , 'Cash ' ),
(5 , 101 , 'Card ' )
alter table tran1 add NewType varchar(100)
Update tran1 set NewType ='Only card' where Customerid IN (
select d.custid from (
select Customerid as custid,SUM(case when [Type]='Card' then 1 else 0 end) card
,SUM(case when [Type]='Cash' then 1 else 0 end) cash
from tran1
group by Customerid)d
where d.card=1
)
Update tran1 set NewType ='Only Cash' where Customerid IN (
select d.custid from (
select Customerid as custid,SUM(case when [Type]='Card' then 1 else 0 end) card
,SUM(case when [Type]='Cash' then 1 else 0 end) cash
from tran1
group by Customerid)d
where d.cash=1
)
Update tran1 set NewType ='Both' where Customerid IN (
select d.custid from (
select Customerid as custid,SUM(case when [Type]='Card' then 1 else 0 end) card
,SUM(case when [Type]='Cash' then 1 else 0 end) cash
from tran1
group by Customerid)d
where d.card=1 and cash=1
)

question on Group by clause in Sql server

Table: Customer
Name Type Amount
James P 125.00
James P 125.00
James P 125.00
James R 225.00
James R 225.00
Rajiv R 155.00
Rajiv R 155.00
Rajiv R 155.00
Rajiv P 150.00
Rajiv P 150.00
Saran R 175.00
In this table structure I want a output which will give each person’s count of P, count of R, sum of Amount where type = P, Sum of amount where type = R
Any clues for me as stuck up with group by did not help me much in this scenario.
If you want the result as separate records, you simply group on the name and type:
select Name, Type, count(*) as Cnt, sum(Amount) as AmountSum
from Customer
Group by Name, Type
order by Name, Type
Result:
Name Type Cnt AmountSum
James P 3 375.00
James R 2 450.00
Rajiv P 2 300.00
Rajiv R 3 465.00
Saran R 1 175.00
If you want the count and sum for a person in the same record, you have to do some comparisons:
select
Name,
count(case Type when 'P' then 1 else null end) as CntP,
sum(case Type when 'P' then Amount else 0 end) as AmountSumP,
count(case Type when 'R' then 1 else null end) as CntR,
sum(case Type when 'R' then Amount else 0 end) as AmountSumR,
from Customer
Group by Name
order by Name
Result:
Name CntP AmountSumP CntR AmountSumR
James 3 375.00 2 450.00
Rajiv 2 300.00 3 465.00
Saran 0 0.00 1 175.00
One query, no CTE, no derived tables:
SELECT
Name,
SUM(CASE WHEN Type = 'P' THEN 1 ELSE 0 END) AS PCount,
SUM(CASE WHEN Type = 'R' THEN 1 ELSE 0 END) AS RCount,
SUM(CASE WHEN Type = 'P' THEN Amount ELSE 0 END) AS PAmount,
SUM(CASE WHEN Type = 'R' THEN Amount ELSE 0 END) AS RAmount
FROM yourTable
GROUP BY Name
using the
CREATE TABLE customer (name varchar(50), type char(1), amount decimal(6,2));
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'R', 225.00);
INSERT INTO customer VALUES ('James', 'R', 225.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'P', 150.00);
INSERT INTO customer VALUES ('Rajiv', 'P', 150.00);
INSERT INTO customer VALUES ('Saran', 'R', 175.00);
SELECT
Name,
SUM(CASE WHEN Type = 'P' THEN 1 ELSE 0 END) AS PCount,
SUM(CASE WHEN Type = 'R' THEN 1 ELSE 0 END) AS RCount,
SUM(CASE WHEN Type = 'P' THEN Amount ELSE 0 END) AS PAmount,
SUM(CASE WHEN Type = 'R' THEN Amount ELSE 0 END) AS RAmount
FROM customer
GROUP BY Name
James 3 2 375.00 450.00
Rajiv 2 3 300.00 465.00
Saran 0 1 0.00 175.00
Edited Answer: After gbn pointed out a mistake in my original answer
SELECT name,
SUM( CASE WHEN [type] = 'P' THEN 1 ELSE 0 END) CountOfP ,
SUM( CASE WHEN [type] = 'R' THEN 1 ELSE 0 END) CountOfR,
SUM( CASE WHEN [type] = 'P' THEN Amount End) SumOfP ,
SUM( CASE WHEN [type] = 'R' THEN Amount END) SumOfR
FROM customer
GROUP BY name
Original Answer
SELECT name,
COUNT( CASE WHEN [type] = 'P' THEN 1 ELSE 0 END) CountOfP ,
COUNT( CASE WHEN [type] = 'R' THEN 1 ELSE 0 END) CountOfR,
SUM( CASE WHEN [type] = 'P' THEN Amount End) SumOfP ,
SUM( CASE WHEN [type] = 'R' THEN Amount END) SumOfR
FROM customer
GROUP BY name