Adding new column showing size of shipment - sql

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

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;

How to show two calculated columns to an existing table

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.

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

Insert values in a column depending upon cell values Sql

I have a table in SQL database (see below)
Customer ID Nationality
------------------------
10001
10002
10003
10004
10005
and I have a spreadsheet
Customer ID Nationality
------------------------
10001 Russian
10002 Swiss
10003 Italian
10004 French
10005 Swiss
I am trying to write a code that can update /insert values in database so that the database table looks same as spreadsheet.
Try this below update script-
UPDATE your_table
SET Nationality =
CASE
WHEN Customer_ID = 10001 THEN 'Russian'
WHEN Customer_ID = 10002 THEN 'Swiss'
WHEN Customer_ID = 10003 THEN 'Italian'
WHEN Customer_ID = 10004 THEN 'French'
WHEN Customer_ID = 10004 THEN 'Swiss'
ELSE 'Other'
END
WHERE Nationality IS NULL

Query to obtain the maximum primary key ID of a table for each unique value of the customerID column in the same table

I'm trying to run a query that takes obtains the maximum QuestionnaireId value for each unique value in column VendorId.
So for example from this table:
QuestionnaireId VendorId
1 10003
2 10004
3 10004
4 10006
5 10005
6 10007
7 10005
8 10005
I would obtain:
QuestionnaireId VendorId
1 10003
3 10004
8 10005
4 10006
6 10007
I'm using the following code to get the maximum QuestionnaireId, but need another statement alongside it to get the unique VendorIds as well. Note that the statement I've included is just last segment of a large Join function to combine all of my tables into one.
WHERE Questionnaire.QuestionnaireId = (SELECT MAX(Questionnaire.QuestionnaireId) FROM Questionnaire)
Just use aggregation:
select max(q.QuestionnaireId) as QuestionnaireId, VendorId
from Questionnaire
group by VendorId;