Row Number Tsql - sql

I have the following Syntax
select rcp.CalendarPeriodId
,rc.CalendarId
,rcp.CalendarYearId
,rcp.PeriodNumber
,rcp.PeriodStartDate,rcp.PeriodEndDate
,CASE WHEN GETDATE() BETWEEN rcp.PeriodStartDate AND rcp.PeriodEndDate THEN 1 ELSE 0 END AS 'CurrentPeriod'
from RentCalendarPeriod rcp
LEFT JOIN RentCalendarYear rcy ON rcy.CalenderYearId = rcp.CalendarYearId
LEFT JOIN RentCalendar rc ON rc.CalendarId = rcy.CalendarId
What this is doing is that a I have two Calendars (CalenderID 1 = Weekly, CalenderID 2 = Monthly) This is the RentCalendar table.
Each Rent Calendar has a Year (RentCalendarYear table),which in turn each Year has a set of periods.
You will notice that line 47, the final column has been marked as 1 (true) This is because it is the current period.
What I need to do is mark the previous 12 periods for any CalendarId. I was wondering if I could achieve this with ROW_NUMBER, with the field CurrentPeriod WHERE = 1 will be 1 and all periods before will start to be numbered 2, 3, 4, 5 and so on.
I don't know how to do this though.

So something like this:
SELECT * FROM (
select rcp.CalendarPeriodId,rc.CalendarId,rcp.CalendarYearId,rcp.PeriodNumber,rcp.PeriodStartDate,rcp.PeriodEndDate,
ROW_NUMBER() OVER(ORDER BY PeriodStartDate DESC) AS CurrentPeriod
from RentCalendarPeriod rcp
LEFT JOIN RentCalendarYear rcy ON rcy.CalenderYearId = rcp.CalendarYearId
LEFT JOIN RentCalendar rc ON rc.CalendarId = rcy.CalendarId)
WHERE currentperiod <= 12
I'm not sure if I understood you correctly.. this will give you for the latests week 1, second one 2 , third one 3 and so on in CurrentPeriod column

Something like this:
;WITH CTE AS (
SELECT rcp.CalendarPeriodId, rc.CalendarId, rcp.CalendarYearId,
rcp.PeriodNumber, rcp.PeriodStartDate, rcp.PeriodEndDate,
ROW_NUMBER() OVER (ORDER BY rcp.CalendarPeriodId) AS rn,
CASE
WHEN GETDATE() BETWEEN rcp.PeriodStartDate AND
rcp.PeriodEndDate THEN 1
ELSE 0
END AS 'CurrentPeriod'
FROM RentCalendarPeriod rcp
LEFT JOIN RentCalendarYear rcy ON rcy.CalenderYearId = rcp.CalendarYearId
LEFT JOIN RentCalendar rc ON rc.CalendarId = rcy.CalendarId
)
SELECT CalendarPeriodId, CalendarId, CalendarYearId,
PeriodNumber, PeriodStartDate, PeriodEndDate,
'CurrentPeriod',
(t.rn + 1) - c.rn AS rn
FROM CTE AS c
CROSS JOIN (SELECT rn FROM CTE WHERE 'CurrentPeriod' = 1) AS t
WHERE rn BETWEEN t.rn - 11 AND t.rn
This will return 12 records, the one having CurrentPeriod = 1 and the previous 11 records. Field rn enumerates records starting from the one having CurrentPeriod = 1.

Related

Row_number not showing 1 rank

I am using the below code to get the rank but not able to see the 1st rank. I am getting the results 2 and 3.
Select BPMDate,Tenor,TenorStartDays,TenorEndDays,NominalTransacted,
SumofNominalRate,AverageRate,VWAR,rw,SortOrder
FROM
(
SELECT case_id,created_date BPMDate,tenor Tenor,tenor_start_days TenorStartDays,
tenor_end_days TenorEndDays
,nominal_transacted NominalTransacted,sum_of_nominal_rates SumofNominalRate
,average_rate AverageRate,vmar VWAR
,Case when tenor='O/N' Then 1 when tenor='1W' Then 2 when tenor='1M' Then 3
when tenor='3M' Then 4
when tenor='6M' Then 5 when tenor='1Y' Then 6 Else 7 End SortOrder,
row_number() over ( partition by tenor order by created_date desc ) rw
From table1
Where df_type = 'DF1' and to_date(created_date) >= '2020-10-13' and
to_date(created_date) <= '2020-10-13'
) ard
inner join
(
select case_id,case_status from table2
where case_status='Completed') ad
on ard.case_id=ad.case_id
order by sortorder
The column rw is beginning from 2 instead 1
thanks for the support
I think you are filtering it out when you join to ad , If you just select the sub query I think you will be able to see it.

SQL - ROW_NUMBER that is used in a multi-condition LEFT JOIN

Two tables store different properties for each product: CTI_ROUTING_VIEW and ORD_MACH_OPS
They are both organized by SPEC_NO > MACH_SEQ_NO but the format of the Sequence number is different for each table so it can't be used for a JOIN. ORCH_MACH_OPS has MACHINE and PASS_NO, meaning if a product goes through the same machine twice, the row with the higher SEQ_NO will be PASS_NO 2, 3, etc. CTI_ROUTING_VIEW does not offer PASS_NO, but I can achieve the desired result with:
SELECT TOP (1000) [SPEC_NO]
,[SPEC_PART_NO]
,[MACH_NO]
,[MACH_SEQ_NO]
,[BLANK_WID]
,[BLANK_LEN]
,[NO_OUT_WID]
,[NO_OUT_LEN]
,[SU_MINUTES]
,[RUN_SPEED]
,[NO_COLORS]
,[PRINTDIEID]
,[CUTDIEID]
,ROW_NUMBER() OVER (PARTITION BY MACH_NO ORDER BY MACH_SEQ_NO) as PASS_NO
FROM [CREATIVE].[dbo].[CTI_ROUTING_VIEW]
I would think that I could use this artificial PASS_NO as a JOIN condition, but I can't seem to get it to come through. This is my first time using ROW_NUMBER() so I'm just wondering if I'm doing something wrong in the JOIN syntax.
SELECT rOrd.[SPEC_NO]
,rOrd.[MACH_SEQ_NO]
,rOrd.[WAS_REROUTED]
,rOrd.[NO_OUT]
,rOrd.[PART_COMP_FLG]
,rOrd.[SCHED_START]
,rOrd.[SCHED_STOP]
,rOrd.[MACH_REROUTE_FLG]
,rOrd.[MACH_DESCR]
,rOrd.REPLACED_MACH_NO
,rOrd.MACH_NO
,rOrd.PASS_NO
,rWip.MAX_TRX_DATETIME
,ISNULL(rWip.NET_FG_SUM*rOrd.NO_OUT,0) as NET_FG_SUM
,CASE
WHEN rCti.BLANK_WID IS NULL then 'N//A'
ELSE CONCAT(rCti.BLANK_WID, ' X ', rCti.BLANK_LEN)
END AS SIZE
,ISNULL(rCti.PRINTDIEID,'N//A') as PRINTDIEID
,ISNULL(rCti.CUTDIEID, 'N//A') as CUTDIEID
,rStyle.DESCR as STYLE
,ISNULL(rCti.NO_COLORS, 0) as NO_COLORS
,CAST(CONCAT(rOrd.ORDER_NO,'-',rOrd.ORDER_PART_NO) as varchar) as ORD_MACH_KEY
FROM [CREATIVE].[dbo].[ORD_MACH_OPS] as rOrd
LEFT JOIN (SELECT DISTINCT
[SPEC_NO]
,[SPEC_PART_NO]
,[MACH_NO]
,MACH_SEQ_NO
,[BLANK_WID]
,[BLANK_LEN]
,[NO_COLORS]
,[PRINTDIEID]
,[CUTDIEID]
,ROW_NUMBER() OVER (PARTITION BY MACH_NO ORDER BY MACH_SEQ_NO) as PASS_NO
FROM [CREATIVE].[dbo].[CTI_ROUTING_VIEW]) as rCti
ON rCti.SPEC_NO = rOrd.SPEC_NO
and rCti.MACH_NO =
CASE
WHEN rOrd.REPLACED_MACH_NO is null then rOrd.MACH_NO
ELSE rOrd.REPLACED_MACH_NO
END
and rCti.PASS_NO = rOrd.PASS_NO
LEFT JOIN INVENTORY_ITEM_TAB as rTab
ON rTab.SPEC_NO = rOrd.SPEC_NO
LEFT JOIN STYLE_DESCRIPTION as rStyle
ON rStyle.DESCR_CD = rTab.STYLE_CD
LEFT JOIN (
SELECT
JOB_NUMBER
,FORM_NO
,TRX_ORIG_MACH_NO
,PASS_NO
,SUM(GROSS_FG_QTY-WASTE_QTY) as NET_FG_SUM
,MAX(TRX_DATETIME) as MAX_TRX_DATETIME
FROM WIP_MACH_OPS
WHERE GROSS_FG_QTY <> 0
GROUP BY JOB_NUMBER, FORM_NO, TRX_ORIG_MACH_NO, PASS_NO) as rWip
ON rWip.JOB_NUMBER = rOrd.ORDER_NO
and rWip.FORM_NO = rOrd.ORDER_PART_NO
and rWip.TRX_ORIG_MACH_NO = rOrd.MACH_NO
and rWip.PASS_NO = rOrd.PASS_NO
WHERE rOrd.SCHED_START > DATEADD(DAY, -20, GETDATE())
I fixed it by adding a second partition.
ROW_NUMBER() OVER (PARTITION BY SPEC_NO, MACH_NO ORDER BY MACH_SEQ_NO) as PASS_NO

How to select a single row for each unique ID

SQL novice here learning on the job, still a greenhorn. I have a problem I don't know how to overcome. Using IBM Netezza and Aginity Workbench.
My current output will try to return one row per case number based on when a task was created. It will only keep the row with the newest task. This gets me about 85% of the way there. The issue is that sometimes multiple tasks have a create day of the same day.
I would like to incorporate Task Followup Date to only keep the newest row if there are multiple rows with the same Case Number. I posted an example of what my current code outputs and what i would like it to output.
Current code
SELECT
A.PS_CASE_ID AS Case_Number
,D.CASE_TASK_TYPE_NM AS Task
,C.TASK_CRTE_TMS
,C.TASK_FLWUP_DT AS Task_Followup_Date
FROM VW_CC_CASE A
INNER JOIN VW_CASE_TASK C ON (A.CASE_ID = C.CASE_ID)
INNER JOIN VW_CASE_TASK_TYPE D ON (C.CASE_TASK_TYPE_ID = D.CASE_TASK_TYPE_ID)
INNER JOIN ADMIN.VW_RSN_CTGY B ON (A.RSN_CTGY_ID = B.RSN_CTGY_ID)
WHERE
(A.PS_Z_SPSR_ID LIKE '%EFT' OR A.PS_Z_SPSR_ID LIKE '%CRDT')
AND CAST(A.CASE_CRTE_TMS AS DATE) >= '2020-01-01'
AND B.RSN_CTGY_NM = 'Chargeback Initiation'
AND CAST(C.TASK_CRTE_TMS AS DATE) = (SELECT MAX(CAST(C2.TASK_CRTE_TMS AS DATE)) from VW_CASE_TASK C2 WHERE C2.CASE_ID = C.CASE_ID)
GROUP BY
A.PS_CASE_ID
,D.CASE_TASK_TYPE_NM
,C.TASK_CRTE_TMS
,C.TASK_FLWUP_DT
Current output
Desired output
You could use ROW_NUMBER here:
WITH cte AS (
SELECT DISTINCT A.PS_CASE_ID AS Case_Number, D.CASE_TASK_TYPE_NM AS Task,
C.TASK_CRTE_TMS, C.TASK_FLWUP_DT AS Task_Followup_Date,
ROW_NUMBER() OVER (PARTITION BY A.PS_CASE_ID ORDER BY C.TASK_FLWUP_DT DESC) rn
FROM VW_CC_CASE A
INNER JOIN VW_CASE_TASK C ON A.CASE_ID = C.CASE_ID
INNER JOIN VW_CASE_TASK_TYPE D ON C.CASE_TASK_TYPE_ID = D.CASE_TASK_TYPE_ID
INNER JOIN ADMIN.VW_RSN_CTGY B ON A.RSN_CTGY_ID = B.RSN_CTGY_ID
WHERE (A.PS_Z_SPSR_ID LIKE '%EFT' OR A.PS_Z_SPSR_ID LIKE '%CRDT') AND
CAST(A.CASE_CRTE_TMS AS DATE) >= '2020-01-01' AND
B.RSN_CTGY_NM = 'Chargeback Initiation' AND
CAST(C.TASK_CRTE_TMS AS DATE) = (SELECT MAX(CAST(C2.TASK_CRTE_TMS AS DATE))
FROM VW_CASE_TASK C2
WHERE C2.CASE_ID = C.CASE_ID)
)
SELECT
Case_Number,
Task,
TASK_CRTE_TMS,
Task_Followup_Date
FROM cte
WHERE rn = 1;
One method used window functions:
with cte as (
< your query here >
)
select x.*
from (select cte.*,
row_number() over (partition by case_number, Task_Followup_Date
order by TASK_CRTE_TMS asc
) as seqnum
from cte
) x
where seqnum = 1;

Overlapping Spans

I am trying to write a query that reorders date ranges around particular spans. It should do something that looks like this
Row Rank Begin Date End Date
1 B 3/24/13 11/1/13
2 A 10/30/13 4/9/15
3 B 3/26/15 12/31/15
and have it become
Row Rank Begin Date End Date
1 B 3/24/13 10/29/13
2 A 10/30/13 4/9/15
3 B 4/10/15 12/31/15
To explain further, the dates in row 2 is ranked higher (A>B), so the dates in row 1 and 3 have to change around the dates in row 2 in order to avoid overlap in dates.
I am using SQL Server 2008 R2
You can use the following query:
;WITH CTE AS (
SELECT Row, Rank, BeginDate, EndDate,
ROW_NUMBER() OVER (ORDER BY BeginDate) AS rn
FROM mytable
), ToUpdate AS (
SELECT c1.Row, c1.Rank, c1.BeginDate, c1.EndDate,
c2.Rank AS pRank, c2.EndDate AS pEndDate,
c3.Rank AS nRank, c3.BeginDate AS nBeginDate
FROM CTE AS c1
LEFT JOIN CTE AS c2 ON c1.rn = c2.rn + 1
LEFT JOIN CTE AS c3 ON c1.rn = c3.rn - 1
WHERE c1.Rank = 'B'
)
UPDATE ToUpdate
SET BeginDate = CASE
WHEN pEndDate IS NULL
THEN BeginDate
WHEN (pEndDate >= BeginDate) AND (pRank = 'A')
THEN DATEADD(d, 1, pEndDate)
ELSE BeginDate
END,
EndDate = CASE
WHEN nBeginDate IS NULL
THEN EndDate
WHEN (nBeginDate <= EndDate) AND (nRank = 'A')
THEN DATEADD(d, -1, nBeginDate)
ELSE EndDate
END
A CTE is initially constructed to assign consecutive, ascending numbers to every record of your table. ROW_NUMBER() window function is used for this purpose.
Using this CTE as a basis we construct ToUpdate. This latter CTE contains date values of current as well as previous and next records.
This LEFT JOIN:
LEFT JOIN CTE AS c2 ON c1.rn = c2.rn + 1
is used to join together with previous record, whereas this one:
LEFT JOIN CTE AS c3 ON c1.rn = c3.rn - 1
is used to join together with next record.
Using CASE expressions we can now easily identify overlaps, and, in case there is one, perform an update.
Demo here
Please use the below query to update the table.
Update table_name
set End_Date = DATEADD(day, -1, select Begin_Date from Table_name where
Row_number = '2')
where row = 1;
You need to change the row numbers every time you run the query. Let me know If this works for you.
I suggest First create a View
CREATE OR REPLACE VIEW tempview AS
SELECT row, begin_date FROM table_name
WHERE row > 1;
Then Use this query to update all the row. If may not update just the first row.
Update table_name
set End_Date = DATEADD(day, -1, select Begin_Date from tempview)
Hope this works

T-sql problem with running sum

I am trying to write T-sql script which will find "open" records for one table
Structure of data is following
Id (int PK) Ts (datetime) Art_id (int) Amount (float)
1 '2009-01-01' 1 1
2 '2009-01-05' 1 -1
3 '2009-01-10' 1 1
4 '2009-01-11' 1 -1
5 '2009-01-13' 1 1
6 '2009-01-14' 1 1
7 '2009-01-15' 2 1
8 '2009-01-17' 2 -1
9 '2009-01-18' 2 1
According to my needs I am trying to show only records after last sum for every one articles where 0 sorting by date of last running sum of zero value. So I am trying to abstract (show) records 5 and 6 for Art_id=1 and record 9 for art_id=2. I am using MSSQL2005 and my table has around 30K records with 6000 distinct values of ART_ID.
In this solution I simply want to find all the rows where there isn't a subsequent row for that Art_id where the running sum was 0. I am assuming we can use the ID as a better tiebreaker than TS, since two rows can come in with the same timestamp but they will get sequential identity values.
;WITH base AS
(
SELECT
ID, Art_id, TS, Amount,
RunningSum = Amount + COALESCE
(
(
SELECT SUM(Amount)
FROM dbo.foo
WHERE Art_id = f.Art_id
AND ID < f.ID
)
, 0
)
FROM dbo.[table name] AS f
)
SELECT ID, Art_id, TS, Amount
FROM base AS b1
WHERE NOT EXISTS
(
SELECT 1
FROM base AS b2
WHERE Art_id = b1.Art_id
AND ID >= b1.ID
AND RunningSum = 0
)
ORDER BY ID;
Complete working query:
SELECT
*
FROM TABLE_NAME E
JOIN
(SELECT
C.ART_ID,
MAX(TS) MAX_TS
FROM
(SELECT
ART_ID,
TS,
COALESCE((SELECT SUM(AMOUNT) FROM TABLE_NAME B WHERE (B.Art_id = A.Art_id) AND (B.Ts < A.Ts)),0) ROW_SUM
FROM TABLE_NAME A) C
WHERE C.ROW_SUM = 0
GROUP BY C.ART_ID) D
ON
(D.ART_ID = E.ART_ID) AND
(E.TS >= D.MAX_TS)
First we calculate running sums for every row:
SELECT
ART_ID,
TS,
COALESCE((SELECT SUM(AMOUNT) FROM TABLE_NAME B WHERE (B.Art_id = A.Art_id) AND (B.Ts < A.Ts)),0) ROW_SUM
FROM TABLE_NAME A
Then we look for last article with 0:
SELECT
C.ART_ID,
MAX(TS) MAX_TS
FROM
(SELECT
ART_ID,
TS,
COALESCE((SELECT SUM(AMOUNT) FROM TABLE_NAME B WHERE (B.Art_id = A.Art_id) AND (B.Ts < A.Ts)),0) ROW_SUM
FROM TABLE_NAME A) C
WHERE C.ROW_SUM = 0
GROUP BY C.ART_ID
You can find all rows where the running sum is zero with:
select cur.id, cur.art_id
from #articles cur
left join #articles prev
on prev.art_id = cur.art_id
and prev.id <= cur.id
group by cur.id, cur.art_id
having sum(prev.amount) = 0
Then you can query all rows that come after the rows with a zero running sum:
select a.*
from #articles a
left join (
select cur.id, cur.art_id, running = sum(prev.amount)
from #articles cur
left join #articles prev
on prev.art_id = cur.art_id
and prev.ts <= cur.ts
group by cur.id, cur.art_id
having sum(prev.amount) = 0
) later_zero_running on
a.art_id = later_zero_running.art_id
and a.id <= later_zero_running.id
where later_zero_running.id is null
The LEFT JOIN in combination with the WHERE says: there can not be a row after this row, where the running sum is zero.