Teradata query pagination - batch every 1000 records - sql

I've this Teradata query:
WITH ID(ROW_NUM) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY PRSN_ID) AS ROW_NUM
FROM MyTable
WHERE ACTIVE_IND = 'Y'
GROUP BY PRSN_ID
)
SELECT ROW_NUM-ROW_NUM MOD 2 AS FirstIndex,
ROW_NUM-(ROW_NUM-1) MOD 2 AS SecondIndex
FROM ID
WHERE ROW_NUM MOD 2=1
This query will generate an ID column, and the result will be something like this:
FirstIndex SecondIndex
0 1
2 3
4 5
. .
. .
etc etc
I would like to change the selection to be a batch through a 1000 records like below:
FirstIndex SecondIndex
0 1000
1001 2000
2001 3000
3001 4000
. .
. .
etc etc
Your help is appreciated.

Your calculation is way to complex:
ROW_NUM-1 AS FirstIndex,
ROW_NUM AS SecondIndex
To get your requested range you simply need to modify the calculation, e.g.
SELECT
CASE WHEN ROW_NUM = 1 THEN 0 ELSE SecondIndex-999 END AS FirstIndex,
(ROW_NUM+2)/2 * 1000 AS SecondIndex
FROM ID
WHERE ROW_NUM MOD 2=1
But what do you want to do with that result, batch what?
Edit:
It's still unclear why you need a 2nd table to calculate the ranges, but this creates ranges starting from 1 for any pagesize of n rows:
WITH ID(ROW_NUM) AS
( -- just to get some rows
SELECT day_of_calendar AS row_num
FROM sys_calendar.CALENDAR
WHERE row_num BETWEEN 1 AND 10
)
SELECT 1000 AS RowsPerPage,
Row_Num AS page_num,
rownum_to - (RowsPerPage-1) AS rownum_from,
page_num * RowsPerPage AS rownum_to
FROM ID
GROUP BY page_num
ORDER BY page_num
RowsPerPage page_num rownum_from rownum_to
1000 1 1 1000
1000 2 1001 2000
1000 3 2001 3000
1000 4 3001 4000
1000 5 4001 5000
1000 6 5001 6000
1000 7 6001 7000
1000 8 7001 8000
1000 9 8001 9000
1000 10 9001 10000

Hi you can try the below query once, this will give you the desired sequence.
select ROW_NUM,FirstIndex, coalesce(case when SecondIndex<1000 then (SecondIndex+2000) else (SecondIndex+1000) end,FirstIndex+1001) as SecondIndex from
(SELECT ROW_NUM,
case when (FirstIndex < 1000) then (FirstIndex+1001) else (FirstIndex+1) end as FirstIndex,
(min(FirstIndex) OVER(ORDER BY FirstIndex ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING)) SecondIndex
FROM (Select (ROW_NUMBER() OVER (ORDER BY PRSN_ID)-1) AS ROW_NUM,(ROW_NUMBER() OVER (ORDER BY PRSN_ID)-1) AS FirstIndex from Mytable GROUP BY PRSN_ID) A) B
order by ROW_NUM;

Related

Incorrect first value when using dense_rank with union all

I want to 'batch' my result (coming from a union of several queries) with a predefined 'batch size' but I can't figure out why the first batch is always incorrect?
For instance with the following code:
DECLARE #BATCHSIZE AS INT = 2;
DECLARE #TEMPTABLE TABLE(ITEMID VARCHAR (10))
INSERT INTO #TEMPTABLE VALUES ('100'),('200'),('300'),('400'),('500'),('600'),('700'),('800'),('900'),('1000'),('1100'),('1200'),('1300'),('1400'),('1500')
;
WITH TEMP AS
(
SELECT * FROM #TEMPTABLE
)
SELECT *, BatchId = (dense_rank() over (order by ITEMID) / #BatchSize + 1)
FROM (
SELECT * From TEMP
UNION ALL
SELECT * From TEMP
) AS temptable
I get a result:
100 1
100 1
1000 2
1000 2
1100 2
1100 2
1200 3
1200 3
1300 3
1300 3
1400 4
1400 4
1500 4
1500 4
200 5
200 5
300 5
300 5
400 6
400 6
500 6
500 6
600 7
600 7
700 7
700 7
800 8
800 8
900 8
900 8
It seems like they're all ok except for batch 1 which only consist of itemid 100?
Must be doing something wrong here..
dense_rank() starts with 1. Shift it to start with 0 :
...
SELECT *, BatchId = (dense_rank() over (order by ITEMID) - 1 )/ #BatchSize + 1
...

Need to select 1 row from each group in sql

am trying to do this query. This is what I have.
My table is: Table
QId InternalId type. priority userid
100 100 1 0 X101
100 100 1 1 X102
100 100 2 0 X103
100 100 2 0 X104
100 100 2 0 X105
100 100 3 0 X106
100 100 3 0 X107
101 101 2 1 X114
101 101 2 0 X115
101 101 3 0 X116
101 101 3 0 X117
For QId and InternalId we have type 1,2,3. I need 1 row for each group based type. Here condition is if priority is 1 then we need take that record. if priority is not set need to take first record.
I need result like below table
QId InternalId type. priority userid
100 100 1 1 X102
100 100 2 0 X103
100 100 3 0 x106
101 101 2 1 X114
101 101 3 0 X116
Can you please help me out in this
Just use row_number():
select t.*
from (select t.*,
row_number() over (partition by QId, InternalId, type order by (select null)) as seqnum
from t
) t
where seqnum = 1;
You can try using row_number()
select * from
(
select *, row_number() over(partition by qid, internalid, type order by priority desc) as rn
from tablename
)A where rn=1
use row_number() window function
select t.* from (select *,row_number()over(partition by QId,InternalId,type order by case when priority=1 then 1 else 2 end) rn
) where t.rn=1
Another approach can be WITH TIES like following.
select top 1 with ties *
from #table
order by row_number() over (partition by QId, InternalId, type order by (select 1))
Online Demo

random row from diapason (1: n) in groups sql

I need select random row from Table using groups and order, but random's row number in group should not be more then constant (for example const = 3).
What I mean:
id time x
1 10:20 1
1 11:21 9
1 16:14 4
1 08:13 8
2 01:20 2
2 21:13 0
For id=1 rows could be:
id time x
1 10:20 1
1 11:21 9
1 08:13 8
BUT not
1 16:14 4 because in order by time it's local number more than 3
for
Id= 2 - any row
WITH cte as (
SELECT *, ROW_NUMBER() OVER (partition by id ORDER BY RANNDOM()) as rn
FROM myTable
)
SELECT *
FROM cte
WHERE rn <= 3
Something like this:
SELECT distinct on (id) *
FROM (select
row_number() over (partition by id order by time ) as up_lim
from tab1) as a
WHERE row_number <= 3
ORDER by id, random() ;

Split rows into multiple rows based on quantity

I have a rows in my table:
id m_id quantity
1 1 1500
2 1 -1000
3 2 -3000
4 2 2000
5 3 400
6 3 -1000
7 4 500
8 4 -500
9 5 1500
I want to create a view that will return this:
id m_id quantity
1 1 500
2 1 1000
3 1 -1000
4 2 -1000
5 2 -2000
6 2 2000
7 3 400
8 3 -400
9 3 -600
10 4 500
11 4 -500
12 5 1500
View will return equal values in positive/negative and split the rest in a separate rows. So two rows are separated into three rows if positive and negative numbers differ for a given m_id.
I think you can use a query like this:
WITH t1 AS (
SELECT *,
LAG(quantity) OVER (PARTITION BY m_id ORDER BY id) as pq, -- Previous quantity based on id
LEAD(quantity) OVER (PARTITION BY m_id ORDER BY id) as nq -- Next quantity based on id
FROM yourTable
), t2 AS (
SELECT id, m_id, 1 as ord,
CASE
-- If sign is changed and quantity is bigger than that use next quantity
WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN -nq
-- If sign is changed and quantity is bigger than that use previous quantity
WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN -pq
-- Else use original quantity
ELSE quantity
END As quantity
FROM t1
UNION ALL -- Add extra rows
SELECT id , m_id,
CASE
-- Set order to be higher than original quantity
WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN 0
-- Set order to be lower than original quantity
WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN 2
END As ord,
-- quantity is difference
CASE
WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN nq + quantity
WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN pq + quantity
END As quantity
FROM t1
WHERE
-- Find differences more
1 = CASE
WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN 1
WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN 1
ELSE 0
END)
SELECT
-- Use new values for id
ROW_NUMBER() OVER (ORDER BY id, ord) As id,
m_id, quantity
FROM t2;

Data not fetch on where clause

I'm facing a problem while applying case..when in where clause in sql. when I put value between 0 and 4 in where clause I get the expected result but when apply case, it fails.
Table name: myTbl
data | amount | date | ReceiptFrequency
A 2000 02-03-1988 Annual
A 2000 02-03-1990 Semiannual
A 2000 02-03-1991 Annual
A 2000 02-03-1992 Annual
create TABLE #Table ( num int NOT NULL, );
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 60 )
INSERT #Table(num)
SELECT n FROM Nbrs
OPTION ( MAXRECURSION 60 )
SELECT *FROM #Table AS x,#Table AS y,myTbl AS d
WHERE (d.ReceiptFrequency<>'Random') AND(x.num BETWEEN 0 AND 1(CASE WHEN d.ReceiptFrequency='Annual' THEN 1 WHEN d.ReceiptFrequency='Quarter' THEN 1 WHEN d.ReceiptFrequency='Month' THEN 12 WHEN d.ReceiptFrequency='SemiAnnual' THEN 2 ELSE 1 END -1))
Why -1 at the end of your CASE..WHEN?
CASE WHEN d.ReceiptFrequency='Annual' THEN 1 WHEN d.ReceiptFrequency='Quarter' THEN 1 WHEN d.ReceiptFrequency='Month' THEN 12 WHEN d.ReceiptFrequency='SemiAnnual' THEN 2 ELSE 1 END -1))