SQL Server : expand range to include missing rows - sql

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

Related

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 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.

Join Runing Sum in TSQL

I would like to join a running sum until a specific time point. E.g. I have two tables
Table A
TimestampOfInterest
2001-01-01
2001-02-01
2001-03-01
Table B
Timestamp Credits
2001-01-01 1
2001-01-05 1
2001-02-10 1
2001-03-15 1
Joining B -> A should lead to
TimestampOfInterest Credits
2001-01-01 0
2001-02-01 2
2001-03-01 3
That is the sum of credits until the given TimestampOfInterest.
Can someone help?
Lazloo
not sure you need join. You can simply do this:
Select TimestampOfInterest,
(Select SUM(Credits)
from TableB
where Timestamp < A.TimeStampOfInterest and Category = A.Category) Credits
From TableA A

Oracle query stumped - derived table

It's been a long time since I've done more than the most basic sql queries. But I ran into this one today and have spent a few hours on it and am stuck with my derived table attempt (this is for an Oracle db). Looking for a few tips. Thx.
TABLE: dtree
DataID Name
-------------
10001 A.doc
10002 B.doc
10003 C.doc
10004 D.doc
TABLE: collections
CollectionID DataID
---------------------
201 10001
201 10002
202 10003
203 10004
TABLE: rimsNodeClassification
DataID RimsSubject RimsRSI Status
---------------------------------------
10001 blah IS-03 Active
10002 blah LE-01 Active
10003 blah AD-02 Active
10004 blah AD-03 Active
TABLE: rsiEventSched
RimsRSI RetStage DateToUse RetYears
--------------------------------------
IS-03 SEM-PHYS 95 1
IS-03 ACT NULL 2
LE-01 SEM-PHYS 94 1
LE-01 INA-PHYS 95 2
LE-01 ACT NULL NULL
LE-01 OFC NULL NULL
LE-02 SEM-PHYS 94 2
Trying to query on CollectionID=201
INTENDED RESULT:
DataID Name RimsRSI Status SEMPHYS_DateToUse INAPHYS_DateToUse SEMPHYS_RetYears INAPHYS_RetYears
-------------------------------------------------------------------------------------------------------
10001 A.doc IS-03 Active 95 null 1 null
10002 B.doc Le-01 Active 94 95 1 2
You don't need a Derived Table, just join the tables (the last using a Left join) and then apply a MAX(CASE) aggregation:
select c.DataID, t.Name, rnc.RimsRSI, rnc.Status,
max(case when res.RetStage = 'SEM-PHYS' then res.DateToUse end) SEMPHYS_DateToUse,
max(case when res.RetStage = 'INA-PHYS' then res.DateToUse end) INAPHYS_DateToUse,
max(case when res.RetStage = 'SEM-PHYS' then res.RetYears end) SEMPHYS_RetYears,
max(case when res.RetStage = 'INA-PHYS' then res.RetYears end) INAPHYS_RetYears
from collections c
join dtree t
on c.DataID = t.DataID
join rimsNodeClassification rnc
on c.DataID = rnc.DataID
left join rsiEventSched res
on rnc.RimsRSI = res.RimsRSI
where c.CollectionID= 201
group by c.DataID, t.Name, rnc.RimsRSI, rnc.Status

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