Update Last Row as First row Value - sql

I have table in below format
SeqID Control_ID Data_Value RowNum
1 SEARCH SEARCH 3
1 BROKERREF BZ815 4
1 SYSTEM 0 5
2 pdp pdp 1
2 test 123 2
2 system 235 3
I want to update the table to be in below format
SeqID Control_ID Data_Value RowNum
1 BROKERREF BZ815 4
1 SYSTEM 0 5
1 SEARCH SEARCH 3
2 test 123 2
2 system 235 3
2 pdp pdp 1
I need to select the top row as a last row for each group of sequence ID.
Note : Control_Id and DataValue Column name will be same for the row which need to be selected as a last row for each unique sequenceID
Thanks in advance.

Use ROW_NUMBER() to locate the first row per SeqID. Then, in an outer query, use CASE expression in the ORDER BY clause to place this row in the last
position within its partition:
SELECT SeqID, Control_ID, Data_Value, RowNum
FROM (
SELECT SeqID, Control_ID, Data_Value, RowNum,
ROW_NUMBER() OVER (PARTITION BY SeqID ORDER BY RowNum) AS rn
FROM mytable ) t
ORDER BY SeqID,
CASE WHEN t.rn = 1 THEN 1 ELSE 0 END,
RowNum
SQL Fiddle Demo

Related

How to use LIMIT to sample rows dynamically

I have a table as follows:
SampleReq
Group
ID
2
1
_001
2
1
_002
2
1
_003
1
2
_004
1
2
_005
1
2
_006
I want my query to IDs based on the column SampleReq, resulting in the following output:
Group
ID
1
_001
1
_003
2
_006
The query should pick any 2 IDs from group 1, any 1 IDs from group 2 and so on (depending on the column SampleReq).
I tried the query using LIMIT, but this gives me an error saying column names cannot be parsed to a limit.
SELECT Group, ID
FROM Table
LIMIT SampleReq
ORDER BY RAND()
One method is row_number():
select t.*
from (select t.*,
row_number() over (partition by samplereq order by random()) as seqnum
from t
) t
where seqnum <= 2 and id = 1 or
seqnum <= 1 and id = 2;

(SQL) Per ID, starting from the first row, return all successive rows with a value N greater than the prior returned row

I have the following example dataset:
ID
Value
Row index (for reference purposes only, does not need to exist in final output)
a
4
1
a
7
2
a
12
3
a
12
4
a
13
5
b
1
6
b
2
7
b
3
8
b
4
9
b
5
10
I would like to write a SQL script that returns the next row which has a Value of N or more than the previously returned row starting from the first row per ID and ordered ascending by [Value]. An example of the final table for N = 3 should look like the following:
ID
Value
Row index
a
4
1
a
7
2
a
12
3
b
1
6
b
4
9
Can this script be written in a vectorised manner? Or must a loop be utilised? Any advice would be greatly appreciated. Thanks!
SQL tables represent unordered sets. There is no definition of "previous" value, unless you have a column that specifies the ordering. With such a column, you can use lag():
select t.*
from (select t.*,
lag(value) over (partition by id order by <ordering column>) as prev_value
from t
) t
where prev_value is null or prev_value <= value - 3;
EDIT:
I think I misunderstood what you want to do. You seem to want to start with the first row for each id. Then get the next row that is 3 or higher in value. Then hold onto that value and get the next that is 3 or higher than that. And so on.
You can do this in SQL using a recursive CTE:
with ts as (
select distinct t.id, t.value, dense_rank() over (partition by id order by value) as seqnum
from t
),
cte as (
select id, value, value as grp_value, 1 as within_seqnum, seqnum
from ts
where seqnum = 1
union all
select ts.id, ts.value,
(case when ts.value >= cte.grp_value + 3 then ts.value else cte.grp_value end),
(case when ts.value >= cte.grp_value + 3 then 1 else cte.within_seqnum + 1 end),
ts.seqnum
from cte join
ts
on ts.id = cte.id and ts.seqnum = cte.seqnum + 1
)
select *
from cte
where within_seqnum = 1
order by id, value;
Here is a db<>fiddle.

DENSE_RANK() Query

I have something similar to the below dataset...
ID RowNumber
101 1
101 2
101 3
101 4
101 5
101 1
101 2
What I would like to get is an additional column as below...
ID RowNumber New
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
I have toyed with dense_rank(), but no such luck.
Gordon already mentioned, you required a column to specify the order of data. If i consider ID as order by column, this following logic may help you to get your desired result-
WITH your_table(ID,RowNumber)
AS
(
SELECT 101,1 UNION ALL
SELECT 101,2 UNION ALL
SELECT 101,3 UNION ALL
SELECT 101,4 UNION ALL
SELECT 101,5 UNION ALL
SELECT 101,1 UNION ALL
SELECT 101,2
)
SELECT A.ID,A.RowNumber,
SUM(RN) OVER
(
ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) +1 New
FROM
(
SELECT *,
CASE
WHEN LAG(RowNumber) OVER(ORDER BY ID) > RowNumber THEN 1
ELSE 0
END RN
FROM your_table
)A
Above will always change the ROW NUMBER if the value in RowNumber decreased than previous one. Alternatively, the same output alsoo can be achieved if you wants to change row number whenever value 1 found. This is bit static option-
SELECT A.ID,A.RowNumber,
SUM(RN) OVER
(
ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) New
FROM(
SELECT *,
CASE
WHEN RowNumber = 1 THEN 1
ELSE 0
END RN
FROM your_table
)A
Output is-
ID RowNumber New
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
SQL tables represent unordered sets. There is no ordering unless a column specifies the ordering.
Assuming you have such a column, you can do what you want simply by counting the number of "1" up to each point:
select t.*,
sum(case when rownumber = 1 then 1 else 0 end) over (partition by id order by <ordering column>) as new
from t;
As Gordon alluded to, there is no default order in your example so it's difficult to imagine how to get a deterministic result (e.g. where the same values supplied to the same query always resulting in the exact same answer.)
This sample data includes a sequential PK column which is used to define the order of this set.
DECLARE #tbl TABLE (PK INT IDENTITY, ID INT, RowNumber INT)
INSERT #tbl(ID, RowNumber) VALUES (101,1),(101,2),(101,3),(101,4),(101,5),(101,1),(101,2);
SELECT t.* FROM #tbl AS t;
Returns:
PK ID RowNumber
----- ------ -----------
1 101 1
2 101 2
3 101 3
4 101 4
5 101 5
6 101 1
7 101 2
This query uses DENSE_RANK to get you what you want:
DECLARE #tbl TABLE (PK INT IDENTITY, ID INT, RowNumber INT)
INSERT #tbl(ID, RowNumber) VALUES (101,1),(101,2),(101,3),(101,4),(101,5),(101,1),(101,2);
SELECT t.ID, t.RowNumber, New = DENSE_RANK() OVER (ORDER BY t.PK - RowNumber)
FROM #tbl AS t;
Returns:
ID RowNumber New
----- ----------- ------
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
Note that ORDER BY New does not affect the plan.
Please try the below
Load the data into Temp table
Select id,RowNumber,Row_number()over(partition by RowNumber Order by id)New from #temp
Order by Row_number()over(partition by RowNumber Order by id),RowNumber

Select row based on max value in column SQL Server

How can I get the output from the input using Microsoft SQL Server? (Basically select the row per ID where vote is max).
Input
ID Label Vote
-----------------------
79185673 2 3
79185673 0 17
79185724 4 5
79185724 1 13
79185724 0 2
79185900 1 17
79185900 2 1
79185900 4 2
79186190 3 3
79186190 2 17
Output
ID Label Vote
-----------------------
79185673 0 17
79185724 1 13
79185900 1 17
79186190 2 17
Use ROW_NUMBER or DENSE_RANK function to give a rank per ID in the descending order of Vote column and then select the rows having rank 1.
I prefer DENSE_RANK function, because it will give same rank for the same Vote values.
Query
;with cte as(
select [rank] = DENSE_RANK() over(
partition by [ID]
order by [Vote] desc
), *
from [your_table_name]
)
select [ID], [Label], [Vote] from cte
where [rank] = 1;

Select the nth most recent row from multiple groups

Using Oracle 12c, I have a table table1 like this:
ID DATA1 DATA2 LAST_UPDATE_TIMESTAMP
1 1 2 time_stamp1
2 1 2 time_stamp2
3 2 1 time_stamp3
4 2 2 time_stamp4
5 1 2 time_stamp5
6 1 1 time_stamp6
7 2 2 time_stamp7
8 1 1 time_stamp8
9 2 1 time_stamp9
10 1 2 time_stamp10
The DATA1 AND DATA2 only has four posssible pairs:
1,1 1,2 2,1 2,2
How to get the IDs of every pair, if ordered by LAST_UPDATE_TIMESTAMP, which are the nth most recent records?
For example, if LAST_UPDATE_TIMESTAMP is already ordered in descending order, then for the most recent, the IDs of four pairs would be 1,3,4,6. For the second most recent, it would be 2,7,8,9.
Solution
Thanks to #kordirko. This is the SQL I end up using
SELECT ID
FROM (
SELECT t.*,
row_number()
over (partition by data1, data2
ORDER BY last_updated_timestamp DESC) as rn
FROM table1 t
)
WHERE rn = n --n means the nth most recent, starts from 1
Try:
SELECT ID, DATA1, DATA2, LAST_UPDATE_TIMESTAMP,
rn -- this is a number of pair: 1-first most recent, 2-second most recent etc.
FROM (
SELECT t.*,
row_number()
over (partition by data1, data2
ORDER BY last_updated_timestamp DESC) as Rn
)
WHERE rn <= 5 -- where 5 is a limit ==> you will get at most 5 most recent records for each pair
If you want only one row returned, then you can use fetch first clause (technically called a "row-limiting clause"). For instance, to get the fifth row for (1, 1):
select t.*
from table1 t
where data1 = 1 and data2 = 1
order by last_update_timestamp desc
offset 4
fetch next 1 row only;
Note that offset is "4" not "5" in this case because four rows are skipped to get to the fifth row. For performance, an index on (data1, data2, last_upate_timestamp) is recommended.