How to show two calculated columns to an existing table - sql

I would like to pull a report that will add two columns to the first two columns of an existing table (Shipment_Info). Shipment_Info has three columns ShipmentID and ItemID and Item_Status. ItemID values are always unique, but ShipmentIDs will repeat because different Items can be in the same shipment, and item status can be in different states (Allocated, Filled and Packed)
I want to run a query that will add two column to the existing table (first two columns). The first new column (Shipment_Size) will show how many unique items there are in that specific shipmentID, and the 2nd new column (Shipment_ready) will show if the entire shipmentID is ready to be shipped. For an shipmentID to be ready to be ItemIDs must be in a "Packed" status. Any help would be greatly appreciated.
DB Table: Shipment_INFO
ShipmentID
ItemID
Item_status
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
Ideal output.
ShipmentID
ItemID
Shipment_Size
Shipment_Ready
10001
20001
1
Yes
10002
20002
2
No
10002
20003
2
No
10003
20004
1
No
10004
20005
3
Yes
10004
20006
3
Yes
10004
20007
3
Yes
10005
20008
2
No
10005
20009
2
No
10006
20010
1
No
Someone help me with getting the Shipment_Size using this query, but I'm struggling to figure out how to integrate the the Shipment_Packed column to the query below.
select s.shipmentID, s.ItemID, i.Shipment_Size
from Shipment_INFO s
inner join ( select shipmentID, count(*) as Shipment_Size
from Shipment_INFO
group by shipmentID ) i on i.shipmentID=s.shipmentID`

Something like this should work
select
shipmentid,
itemid,
count(*) over (partition by shipmentid) as shipment_size,
case
when (
select count(*) from shipment_info si2
where si2.shipmentid = si.shipmentid
and si2.item_status = 'Packed'
) = count(*) over (partition by shipmentid)
then 'Yes'
else 'No'
end as shipment_ready
from
shipment_info si
or:
with
shipment_status as (
select
shipmentid,
count(1) as shipment_size,
sum(case item_status when 'Packed' then 1 else 0 end) as packed_count
from
shipment_info
group by
shipmentid
)
select
si.shipmentid,
si.itemid,
ss.shipment_size,
case ss.packed_count
when ss.shipment_size then 'Yes'
else 'No'
as shipment_ready
from
shipment_info si
join
shipment_status ss on ss.shipmentid = si.shipmentid

example for you :
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
from Shipment_INFO
group by ShipmentID,Item_status,ItemID
demo :https://dbfiddle.uk/80HA0Njd

You want to select all rows, but for each row look at its whole shipment. To do this use analytic funtions with OVER (PARTITION BY shipmentid):
select
shipmentid,
itemid,
count(*) over (partition by shipmentid) as shipment_size,
min(item_status) over (partition by shipmentid) = 'Packed' as shipment_ready
from shipment_info
order by itemid;
I am using a trick here. 'Packed' is the last status in alphabetical order. So if the minimum status for a shipment is 'Packed', then all its items are packed and the shipment is ready.

Related

How do I join 2 tables and calculate 1 new column

I'm need to get 3 new columns with my SQL query. The first 2 columns only requires 1 table (Shipment_Info), but the 3rd column requires the 2nd table (Item_Info).
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.
Shipment_Info_table:
Shipment_Info has three columns ShipmentID and ItemID and Item_Status. ItemID values are always unique, but ShipmentIDs will repeat because different Items can be in the same shipment, and item status can be in different states (Allocated, Filled and Packed).
Item_Info table:
Item_Info has two columns. ItemID, Operation, Op_time. ItemIDs will repeat because this table shows the different operations that have occurred to this itemID and the associated times.
DB Table: Shipment_INFO
ShipmentID
ItemID
Item_status
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
DB Table: Item_Info
ItemID
Item_status
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
10001
20001
1
Yes
No
10002
20002
2
No
Yes
10002
20003
2
No
Yes
10003
20004
1
No
Yes
10004
20005
3
Yes
Yes
10004
20006
3
Yes
No
10004
20007
3
Yes
Yes
10005
20008
2
No
No
10005
20009
2
No
Yes
10006
20010
1
No
Yes
The code below gets me the first two columns, but I'm having trouble on how to join 2nd table and get the 3 column. Any help would be greatly appreciated.
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
from Shipment_INFO
group by ShipmentID,Item_status,ItemID
I think you just want a simple case expression using exists:
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
from Shipment_INFO si
group by ShipmentID, Item_status, ItemID;

Adding new column showing size of shipment

I would like to pull a report that will add another column to an existing table. I have a table that has two columns ShipmentID and ItemID. ItemID values are always unique, but ShipmentIDs will repeat because different Items can be in the same shipment. I want to run a query that will add a column to the existing table that will show how many unique items are in that specific shipmentID.
DB Table: Shipment_INFO
ShipmentID
ItemID
10001
20001
10002
20002
10002
20003
10003
20004
10004
20005
10004
20006
10004
20007
10005
20008
10005
20009
10006
20010
Ideal output.
ShipmentID
ItemID
Shipment_Size
10001
20001
1
10002
20002
2
10002
20003
2
10003
20004
1
10004
20005
3
10004
20006
3
10004
20007
3
10005
20008
2
10005
20009
2
10006
20010
1
I believe I need to create a temporary table with ShipmentID and the associated counts using:
select shipmentID, count(*)
from Shipment_INFO
group by shipmentID
and then join this table to the original Shipment_INFO table to get the output I am looking for. I could look into how to create temporary tables, but would like to know if there is a way to do this without a temp table.
One way to do it is with nested joins.
And you already have what you are looking for:
select s.shipmentID, s.ItemID, i.Shipment_Size
from Shipment_INFO s
inner join (
select shipmentID, count(*) as Shipment_Size
from Shipment_INFO
group by shipmentID
) i on i.shipmentID=s.shipmentID
No need to read the table more one once, use a count over partition window function:
select ShipmentID, ItemID, count(*) over (partition by ShipmentID)
from Shipment_INFO
See demo at: https://dbfiddle.uk/aOFW8HFx

How to find out first product item client purchased whose bought specific products?

I want to write a query to locate a group of clients whose purchased specific 2 product categories, at the same time, getting the information of first transaction date and first item they purchased. Since I used group by function, I could only get customer id but not first item purchase due to the nature of group by. Any thoughts to solve this problem?
What I have are transaction tables(t), customer_id tables(c) and product tables(p). Mine is SQL server 2008.
Update
SELECT t.customer_id
,t.product_category
,MIN(t.transaction_date) AS FIRST_TRANSACTION_DATE
,SUM(t.quantity) AS TOTAL_QTY
,SUM(t.sales) AS TOTAL_SALES
FROM transaction t
WHERE t.product_category IN ('VEGETABLES', 'FRUITS')
AND t.transaction_date BETWEEN '2020/01/01' AND '2022/09/30'
GROUP BY t.customer_id
HAVING COUNT(DISTINCT t.product_category) = 2
**Customer_id** **transaction_date** **product_category** **quantity** **sales**
1 2022-05-30 VEGETABLES 1 100
1 2022-08-30 VEGETABLES 1 100
2 2022-07-30 VEGETABLES 1 100
2 2022-07-30 FRUITS 1 50
2 2022-07-30 VEGETABLES 2 200
3 2022-07-30 VEGETABLES 3 300
3 2022-08-01 FRUITS 1 50
3 2022-08-05 FRUITS 1 50
4 2022-08-07 FRUITS 1 50
4 2022-09-05 FRUITS 2 100
In the above, what I want to show after executing the SQL query is
**Customer_id** **FIRST_TRANSACTION_DATE** **first_product_category** **TOTAL_QUANTITY** **TOTAL_SALES**
2 2022-07-30 VEGETABLES, FRUITS 4 350
3 2022-07-30 VEGETABLES 5 400
Customer_id 1 and 4 will not be shown as they only purchased either vegetables or fruits but not both
Check now, BTW need find logic with product_category
select CustomerId, transaction_date, product_category, quantity, sales
from(
select CustomerId, transaction_date, product_category , sum(quantity) over(partition by CustomerId ) as quantity , sum(sales) over(partition by CustomerId ) as sales, row_number() over(partition by CustomerId order by transaction_date ASC) rn
from(
select CustomerId, transaction_date, product_category, quantity, sales
from tablee t
where (product_category = 'FRUITS' and
EXISTS (select CustomerId
from tablee tt
where product_category = 'VEGETABLES'
and t.CustomerId = tt.CustomerId)) OR
(product_category = 'VEGETABLES' and
EXISTS (select CustomerId
from tablee tt
where product_category = 'FRUITS'
and t.CustomerId = tt.CustomerId)))x)over_all
where rn = 1;
HERE is FIDDLE

SQL Server : expand range to include missing rows

I have a table (A) where the PK is an int:
Entry No. Date Product
-------------------------------
10001 1/1/19 Jeans
10002 1/1/19 Shoes
10003 2/1/19 Jeans...
I have another table (B) with sample data below (all values are int):
ID Begin End
-------------------
1 10001 10003
2 10004 10007
3 10008 10019...
I need to find the [ID] in table B for each [Entry No.] in table A.
I believe this requires unpivoting table B so [Begin] and [End] are in the same column then 'expanding' the rows so there's a row for every int:
ID Entry No.
-------------
1 10001
1 10002
1 10003
2 10004
2 10005
2 10006
2 10007
3 10008...
I could then join this to Table A on [Table A].[Entry No.] = [Table B].[Entry.No.]
My unpivot code:
SELECT
ID, [Entry No.]
FROM
(SELECT * FROM [Table B]) AS piv
UNPIVOT
([Entry No.] FOR values IN (Begin, End)) AS unpvt
Is there a better way of doing this? If not, can you please help me with how to 'expand' table B?
Use JOIN:
select a.*, b.*
from a join
b
on a.entry_no between b.begin_entry and b.end_entry

Using cursor for fetching multiple rows and setting its data in columns

My scenario is I have to populate data into a table by performing join on two tables A and B on the basis of column quoteid and compid
Table A
------------------------------
quoteid compid ................
10004 1
10004 1
10004 1
10004 22
10004 22
10004 22
Table B
------------------------------------
quoteid compid quartercode cost
10004 1 1q10 14
10004 1 2q09 10
10004 1 3q10 12
10004 22 4q12 32
10004 22 3q11 30
10004 22 2q11 43
Now, the result of select query should be like
quoteid compid quarter1cost quarter2cost quarter3cost
10004 1 10 14 12
10004 22 43 30 32
The concept to select cost for quarter is with quartercode which is combination of quarter in year(1st,2nd...) and last two digits of year. So, oldest quarter will with quarter1 , second oldest will be quarter2 and most recent will be quarter3. Here, there cost will be available for only 3 recent quarters due to join conditions. For example, here for quoteid 10004 and compid 1, quarter1 will be 2q09, quarter2 will be 1q10 and quarter3 will be 3q10 and hence the cost.
I am trying to do it with cursor. But since I am new so unable to get the desired result.
Table A seems to have nothing to do with your result.
The basic idea is to use row_number() and conditional aggregation. This is complicated because you the quarter identifier is stored backwards, so it doesn't sort correctly. But you can still do it:
select quoteid, compid,
max(case when seqnum = 1 then cost end) as cost_q1,
max(case when seqnum = 2 then cost end) as cost_q2,
max(case when seqnum = 3 then cost end) as cost_q3
from (select b.*,
row_number() over (partition by quoteid, compid
order by substr(quartercode, 1, 1), substr(quartercode, 3, 2)
) as seqnum
from b
) b
group by quoteid, compid