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

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

Related

Expression within case statement using two tables

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

Indicate a row that cause an abnormal case (SQL)

I have a result as below using the following script:
SELECT
id, (2022 - age) yearId, age, [value],
CASE
WHEN LAG([value], 1, 0) OVER (PARTITION BY id ORDER BY [age]) = 0
THEN 'Base'
WHEN [value] > LAG([value], 1, -1) OVER (PARTITION BY id ORDER BY [age])
THEN 'Increasing'
WHEN [value] = LAG([value], 1, -1) OVER (PARTITION BY id ORDER BY [age])
THEN 'No Change'
ELSE 'Decreasing'
END AS [Order]
FROM Test
Values
And I manage to get a group of ids with an id causing a "flip: decreasing and then increasing or the other way around" as:
Abnormal Case
Now I want to print out the same result as above but with a column indicates the row that cause the flip, something like this (the row causes the flip should be place at the top of each partition):
Id
age
value
flip
1
4
3
1
1
0
5
0
1
1
4
0
1
2
3
0
1
3
2
0
1
5
3
0
1
6
4
0
Thank you!
Expanding your existing logic to get the previous order value then conditionally ordering
with cte as
(
SELECT
id, (2022 - age) yearId, age, [value],
CASE
WHEN LAG([value], 1, 0) OVER (PARTITION BY id ORDER BY [age]) = 0
THEN 'Base'
WHEN [value] > LAG([value], 1, -1) OVER (PARTITION BY id ORDER BY [age])
THEN 'Increasing'
WHEN [value] = LAG([value], 1, -1) OVER (PARTITION BY id ORDER BY [age])
THEN 'No Change'
ELSE 'Decreasing'
END AS [Order]
FROM T1
) ,
cte1 as
(select cte.*,concat(cte.[order], lag([order]) over (partition by id order by age)) concatlag
from cte)
select * ,
case when concatlag in('IncreasingDecreasing','DecreasingIncreasing') then 1 else 0 end
from cte1
order by
case when concatlag in('IncreasingDecreasing','DecreasingIncreasing') then 1 else 0 end desc,
age

Insert records from multiple rows of table to multiple columns of other table

I have an existing table structure with sample data like
Id
BookingId
Value
TypeId
AddedTime
1
100
10
T1
2021-03-22 08:51:52.6333333
2
100
20
T2
2021-03-22 08:50:55.8133333
3
100
30
T3
2021-03-22 08:50:22.1033333
4
200
50
T1
2021-03-22 08:50:22.1033333
5
200
60
T2
2021-03-22 08:50:22.1000000
6
200
70
T3
2021-03-22 08:50:22.0800000
and now data model is changed and it becomes like
Id
BookingId
Type1Value
Type2Value
Type3Value
AddedTime
Please help me what would be query to copy data from previous table to new table.
Output should be something like
Id
BookingId
Type1Value
Type2Value
Type3Value
AddedTime
1
100
10
20
30
2
200
50
60
70
I tried:
select BookingId
, Type1Value = max(case when RN=1 then Value else null end)
, Type2Value = max(case when RN=2 then Value else null end)
, Type3Value = max(case when RN=3 then Value else null end)
from (
select *
, rn = Row_Number() over (Partition By TypeId Order by AddedTime)
from Values_M
) a
where rn <= 3
group by BookingId
This will gives you the required result using conditional case expression.
Using row_number() to generate new running number Id
select Id = row_number() over (order by BookingId),
BookingId = BookingId,
Type1Value = max(case when TypeId = 'T1' then Value end),
Type2Value = max(case when TypeId = 'T2' then Value end),
Type3Value = max(case when TypeId = 'T3' then Value end),
AddedTime = min(AddedTime)
from Values_M
group by BookingId
dbfiddle
select BookingId, min(T1) as Type1Value, min(T2) as Type2Value, min(T3) as Type3Value
from table1
pivot (sum(value) for Typeid in (T1,T2,T3)) as PivotTable
group by BookingId
You can use row_number() and self join.
with cte as (
select Id, BookingId, [Value], TypeId, AddedTime
, row_number() over (partition by BookingId order by id asc) rn
from Values_M
)
select C1.rn, C1.BookingId, C1.[Value] Type1Value, C2.[Value] Type2Value, C3.[Value] Type3Value, C1.AddedTime
from cte C1
inner join cte C2 on C2.BookingId = C1.BookingId and C2.rn = 2
inner join cte C3 on C3.BookingId = C1.BookingId and C3.rn = 3
where C1.rn = 1
order by BookingId asc;

Pivot function returning null values

I want to show all three rows in 1st row so i used pivot in the query
**output pic is attached **
SELECT [Container Number],ReadTimee,Locationn,Trailer FROM
(SELECT [Container Number],ReadTime,Location FROM #temp )as Tab1
PIVOT
(
MAX(ReadTime) FOR Location IN (Trailer,ReadTimee,Locationn)) AS Tab2
But using above query returning null
.The output pic is shown below
I want a output Like this
ReadTime Location Trailer Container Number ReadTime Location Trailer Container Number ReadTime Location Trailer Container Number
2019-02-27 03:17:21.033 CUSTOM 1 ZIMU1374787,TRHU3437713 2019-02-27 06:10:35.470 ZERO 1 ZIMU1374787,TRHU3437713 2019-02-27 07:30:47.407 CFS 1 ZIMU1374787,TRHU3437713
Try this:
SELECT Trailer, [Container Number], [CUSTOM] = MAX(CASE WHEN Location = 'CUSTOM' THEN ReadTime ELSE NULL END),
[ZERO] = MAX(CASE WHEN Location = 'ZERO' THEN ReadTime ELSE NULL END),
[CFS] = MAX(CASE WHEN Location = 'CFS' THEN ReadTime ELSE NULL END)
FROM #tmp
GROUP BY Trailer, [Container Number]
Above query returns:
Trailer Container Number CUSTOM ZERO CFS
1 ZIMU1374787,TRHU3437713 2019-02-27 03:17:21.033 2019-02-27 06:10:35.470 2019-02-27 07:30:47.407
You can use MAX method to get necessary columns:
SELECT
MAX(CASE WHEN q.RowNumber = 1 THEN q.ReadTime ELSE NULL END) AS ReadTime
, MAX(CASE WHEN q.RowNumber = 1 THEN q.Location ELSE NULL END) AS Location
, MAX(CASE WHEN q.RowNumber = 1 THEN q.Trailer ELSE NULL END) AS Trailer
, MAX(CASE WHEN q.RowNumber = 1 THEN q.ContainerNumber ELSE NULL END) AS ContainerNumber
, MAX(CASE WHEN q.RowNumber = 2 THEN q.ReadTime ELSE NULL END) AS ReadTime
, MAX(CASE WHEN q.RowNumber = 2 THEN q.Location ELSE NULL END) AS Location
, MAX(CASE WHEN q.RowNumber = 2 THEN q.Trailer ELSE NULL END) AS Trailer
, MAX(CASE WHEN q.RowNumber = 2 THEN q.ContainerNumber ELSE NULL END) AS ContainerNumber
, MAX(CASE WHEN q.RowNumber = 3 THEN q.ReadTime ELSE NULL END) AS ReadTime
, MAX(CASE WHEN q.RowNumber = 3 THEN q.Location ELSE NULL END) AS Location
, MAX(CASE WHEN q.RowNumber = 3 THEN q.Trailer ELSE NULL END) AS Trailer
, MAX(CASE WHEN q.RowNumber = 3 THEN q.ContainerNumber ELSE NULL END) AS ContainerNumber
FROM
(
SELECT
*
, ROW_NUMBER() OVER(PARTITION BY T.Trailer ORDER BY T.Trailer) AS RowNumber
FROM #Table AS T
)AS q
Let me show an example:
DECLARE #Table TABLE
(
ReadTime DATETIME,
[Location] VARCHAR(50),
Trailer INT,
ContainerNumber VARCHAR(50)
)
INSERT INTO #Table
(
ReadTime,
Location,
Trailer,
ContainerNumber
)
VALUES
( '2019-02-23 12:22:35.490', 'CUSTOM', 1, 'ZIMU1' )
, ( '2019-02-24 12:22:35.490', 'ZERO', 1, 'ZIMU2' )
, ( '2019-02-25 12:22:35.490', 'CFS', 1, 'ZIMU3')
And use the above query to get the desired output:

sql select and compare most recent and nth most recent value but exclude when value has been repeated for more than three months

I am using the following query to select the most recent and 3rd most recent values from a table grouped by their MeterNumber. The user supplies a month and day which determines the highest value returned.
The purpose of the query is to look at the Water Reads for a Meter and see if they are the same over a 3 month period. If so no consumption is happening and the meter is likely broken.
My problem is that I'd also like to exclude any meter's that have had the same read for the 4th, 5th, 6th, ... most recent read dates because these meters are likely unused.
Any help would be greatly appreciated! I'm very new to this so perhaps there is a much more efficient/better way to accomplish this.
I'm using MS SQL 2012.
SELECT
MeterNumber,
MAX(WaterRead) AS CurrentRead,
MAX(ReadDate) AS CurrentReadDate,
MIN(WaterRead) AS nthLastRead,
MIN(ReadDate) AS nthLastReadDate
From
(SELECT MeterNumber, ReadDate, WaterRead
FROM (
SELECT MeterNumber, ReadDate, WaterRead, Rank() over (Partition BY MeterNumber ORDER BY ReadDate DESC ) AS myRank
FROM WaterReads
) WaterReads WHERE myRank <= 3 ) a
Group By MeterNumber
Having MAX(WaterRead) - MIN(WaterRead) = 0 AND MAX(WaterRead) != 0 AND MIN(WaterRead) != 0 AND MIN(ReadDate) <> MAX(ReadDate)
AND MONTH(MAX(ReadDate)) = 6 AND DAY(MAX(ReadDate)) = 25
ORDER BY MeterNumber, CurrentReadDate
This returns:
MeterNumber CurrentRead CurrentReadDate nthLastRead nthLastReadDate
80021139 12103 2013-06-25 12103 2013-04-24
80029512 5347 2013-06-25 5347 2013-04-24
80038245 304304 2013-06-25 304304 2013-04-24
80044119 46250 2013-06-25 46250 2013-04-24
80048357 6707 2013-06-25 6707 2013-04-24
You're on the right track. You can use max(case when...) to pluck out the specific previous periods to compare. Like so:
SELECT
meternumber,
MAX(CASE WHEN myrank = 1 THEN readdate ELSE NULL END) curr_date,
MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) curr_read,
MAX(CASE WHEN myrank = 4 THEN readdate ELSE NULL END) ago3_date,
MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) ago3_read,
MAX(CASE WHEN myrank = 7 THEN readdate ELSE NULL END) ago6_date,
MAX(CASE WHEN myrank = 7 THEN waterread ELSE NULL END) ago6_read
FROM
(
SELECT MeterNumber,
ReadDate,
WaterRead,
Rank() over (Partition BY MeterNumber ORDER BY ReadDate DESC ) AS myRank
FROM WaterReads
WHERE readdate <= '20130625'
) AS a
GROUP BY
meternumber
HAVING
MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) = MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END)
AND MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) > MAX(CASE WHEN myrank = 7 THEN waterread ELSE NULL END)
AND MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) > 0
SQLFiddle here
Or, a little easier to read, but with an additional subquery:
SELECT
meternumber,
curr_date,
curr_read,
ago3_date,
ago3_read,
ago6_date,
ago6_read
FROM
(
SELECT
meternumber,
MAX(CASE WHEN myrank = 1 THEN readdate ELSE NULL END) curr_date,
MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) curr_read,
MAX(CASE WHEN myrank = 4 THEN readdate ELSE NULL END) ago3_date,
MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) ago3_read,
MAX(CASE WHEN myrank = 7 THEN readdate ELSE NULL END) ago6_date,
MAX(CASE WHEN myrank = 7 THEN waterread ELSE NULL END) ago6_read
FROM
(
SELECT MeterNumber,
ReadDate,
WaterRead,
Rank() over (Partition BY MeterNumber ORDER BY ReadDate DESC ) AS myRank
FROM WaterReads
WHERE readdate <= '20130625'
) AS a
GROUP BY
meternumber
) AS b
WHERE
curr_read = ago3_read
AND curr_read > ago6_read
AND ago3_read > 0