Setting a column with a Page value for every million rows - sql-server

Users
-RowID
-PageNumber
-...
For each 1 million ROWS, I want TO SET the value OF the PageNumber WITH an increment number.
So 1 to 1 000 000 will have a PageNumber of 1. Then from 1 000 001 to 2 000 000 will have a PageNumber of 2 and so on...

Just some math using a running row number.
SELECT
FLOOR((ROW_NUMBER() OVER (ORDER BY (SELECT 1)) + 999999) / 1000000)
FROM
YourTable;

You can make use of ntile function to get your expected output. First you need to set a static value of 1 million and then get the number of partitions required based on total count / total partitions.
Declare #valueset int = 1000000
Declare #totalcount bigint = (Select count(1) total from yourtable)
Declare #totalpartition int = (select ceiling(#totalcount*1.0/#valueset*1.0))
--select #totalpartition
select ntile(#totalpartition) over (order by somecolumn ) pagenumber,* from yourtable

As you confirmed RowId is a auto increment column, you can do this to update your new column-
SELECT:
SELECT *,
CASE
WHEN ROW_NUMBER() OVER(ORDER BY RowId) %100000 = 0
THEN ROW_NUMBER() OVER(ORDER BY RowId) /100000
ELSE ROW_NUMBER() OVER(ORDER BY RowId) /100000 + 1
END
FROM your_table
UPDATE:
WITH CTE AS (
SELECT RowId,
CASE
WHEN ROW_NUMBER() OVER(ORDER BY RowId) %100000 = 0
THEN ROW_NUMBER() OVER(ORDER BY RowId) /100000
ELSE ROW_NUMBER() OVER(ORDER BY RowId) /100000 + 1
END NV
FROM your_table
)
UPDATE A
SET A.NewColumnName = B.NV
FROM your_table A
INNER JOIN CTE B ON A.RowId= B.RowId
Caution: Please try with test data first.

Related

T-SQL : how to split order detail quantities out into separate rows

I have following order detail query
OrderId item Quantity
----------------------------------
3402323 Item1 3
3402323 Item2 1
3402324 Item1 2
And the results I need are
OrderId item Quantity
----------------------------------
3402323-1 Item1 1
3402323-2 Item1 1
3402323-3 Item1 1
3402323-4 Item2 1
3402324-1 Item1 1
3402324-2 Item1 1
Is there a way to do this without using a temp table and populating it with a cursor?
I would personally use a Tally. These are far faster than a rCTE, especially if (in this scenario) you have large values for Quantity, and can't suffer from hitting the max recursion problem, as they aren't recursive.
WITH YourTable AS(
SELECT *
FROM (VALUES(3402323,'Item1',3),
(3402323,'Item2',1),
(3402324,'Item1',2))V(OrderID,Item,Quantity)),
N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT MAX(Quantity) FROM YourTable)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3) --1000 rows
SELECT CONCAT(YT.OrderID,'-',T.I) AS OrderID,
YT.Item,
1 AS Quantity
FROM YourTable YT
JOIN Tally T ON YT.Quantity >= T.I;
Use a recursive subquery:
with cte as (
select orderid, item, quantity, 1 as n
from t
union all
select orderid, item, quantity, n + 1
from cte
where n < quantity
)
select orderid, item, 1 as quantity
from cte;
If your quantities exceed 100, then you need to add option (maxrecursion 0).
If you have SQL Server 2016 or later you can utilize the STRING_SPLIT function and the REPLICATE function to achieve the result you are looking for. The REPLICATE function can be used to create a comma delimited string that repeats N number of times (this will be your quantity). The STRING_SPLIT function can be used to split the string into N number of records you can join on.
The following example shows how this would work with your data.
DECLARE #orders TABLE
(
OrderId VARCHAR(50)
,Item VARCHAR(50)
,Quantity INT
)
INSERT INTO #orders
SELECT 3402323 ,'Item1', 3 UNION ALL
SELECT 3402323 ,'Item2', 1 UNION ALL
SELECT 3402324 ,'Item1', 2
SELECT
OrderId = O.OrderId + '-' + CAST( (ROW_NUMBER() OVER (PARTITION BY O.OrderId ORDER BY O.Item, OE.RepeatId) ) AS VARCHAR(50) )
,O.Item
,Quantity = 1
FROM
#orders O
CROSS APPLY
(
SELECT RepeatId = ROW_NUMBER() OVER (ORDER BY [value])
FROM
STRING_SPLIT(REPLICATE ( ',', O.Quantity - 1), ',')
) OE

how to select last rows where one certain value exist but not if it's in between

I have this table. With case#, Linenumber and code#.
case# Linenumber Code#
99L1HV 1 1510
99L1HV 2 4320
99PX58 1 1510
99PX58 2 4320
99PX58 3 4500
99PX59 1 1510
99PX59 2 918
99PX59 3 4320
How can I get the records with the last LineNumber per case# where code = 4320
The output should be like this
case# Linenumber Code
99L1HV 2 4320
99PX59 3 4320
Using ROW_NUMBER to get a number that's in the opposite order of the linenumber per case#.
Then the last lines will have RN = 1
SELECT [case#], Linenumber, [Code#]
FROM
(
SELECT [case#], Linenumber, [Code#],
ROW_NUMBER() OVER (PARTITION BY [case#] ORDER BY Linenumber DESC) AS RN
FROM yourtable
) q
WHERE RN = 1
AND [Code#] = 4320
ORDER BY [case#];
Or the more concise version.
Using a TOP 1 WITH TIES in combination with an ORDER BY ROW_NUMBER.
SELECT *
FROM
(
SELECT TOP 1 WITH TIES [case#], Linenumber, [Code#]
FROM yourtable
ORDER BY ROW_NUMBER() OVER (PARTITION BY [case#] ORDER BY Linenumber DESC)
) q
WHERE [Code#] = 4320
ORDER BY [case#];
cte is to generate a running number by case#. rn = 1 will be the last row for each case#
; with cte as
(
select *, rn = row_number() over (partition by [case#] order by linenumber desc)
from yourtable
)
select *
from cte
where rn = 1
and [code#] = 4320
declare #t table (
CaseNumber varchar(10),
LineNumber int,
CodeNumber int
);
-- Filling the table with data, skipped
select t.*
from #t t
where t.CodeNumber = 4320
and not exists (
select 0 from #t x
where x.CaseNumber = t.CaseNumber
and x.LineNumber > t.LineNumber
);
with cte as
(select case#, max(linenumber)
from source_table
group by case#)
select t1.*
from source_table t1 inner join cte t2
on t1.case# = t2.case# and t1.linenumber = t2.linenumber
where t1.Code# = 4320

select max value in each 5 rows

My total rows are variable and not fixed , So there are N rows and I want to separate each 5 rows as a group and select the max value of price in following table in SQL.
Date Price
20170101 100
20170102 110
20170103 90
20170105 80
20170109 76
20170110 50
20170111 55
20170113 80
20170115 100
20170120 99
20170121 88
20170122 98
20170123 120
So in first 5 group the max price is 110 , and second group is 100, and last group max price is 120.
Use a common table expression to group them.
WITH CTE AS (SELECT RANK() OVER (ORDER BY Date) AS Rank, Price
FROM yourtable)
SELECT (Rank - 1) / 5 AS GroupedDate, MAX(Price) AS MAXPRICE
FROM CTE
GROUP BY ((Rank - 1) / 5);
Output
GroupedDate MAXPRICE
0 110
1 100
2 120
SQL Fiddle: http://sqlfiddle.com/#!6/b5857/3/0
You can use row_number as below
;With cte as (
Select *, Bucket = Sum(RowN) over(Order by [date]) from (
Select *, RowN = case when row_number() over(order by [date]) % 5 = 0 then 1 else 0 end from #data1
) a
) Select top (1) with ties [Date], [Price]
from cte
order by row_number() over (partition by Bucket order by Price desc)
You could use:
SELECT grp, MAX(Price) AS price
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY DATE) / 5 AS grp FROM tab) sub
GROUP BY grp;
-- OUTPUT
grp price
0 110
1 100
2 120
Rextester Demo
*assuming that date is unique
EDIT:
As in something like : 20170101 - 20170109 110
SELECT
CONVERT(VARCHAR(8),MIN(DATE),112) + '-' + CONVERT(VARCHAR(8),MAX(date),112)
, MAX(Price) AS price
FROM (SELECT *, (ROW_NUMBER() OVER(ORDER BY DATE) ) / 5 AS grp FROM tab) sub
GROUP BY grp;
Output:
20170101-20170105 110
20170109-20170115 100
20170120-20170123 120
Rextester Demo2

Select a random row from each group SQL Server

I have a table like below
ID Code Age
----------------
1 4758 21
1 7842 14
1 9821 23
1 6842 9
2 8472 24
2 7558 31
2 7841 28
3 7881 38
3 8794 42
3 4871 43
For each ID, I want to select one of the rows at random like so
ID Code Age
----------------
1 7842 14
2 7841 28
3 4871 43
Is this possible in SQL Server?
select top 1 with ties id,code,age
from
table
order by row_number() over (partition by id order by rand())
Update: as per this Return rows in random order, you have to use NEWId,since RAND() is fixed for the duration of the SELECT on MS SQL Server.
select top 1 with ties id,code,age
from
table
order by row_number() over (partition by id order by NEWID())
Use Newid() in order by clause of Row_number()
SELECT [ID], [Code], [Age]
FROM (SELECT *,
Row_number()
OVER(
PARTITION BY ID
ORDER BY Newid()) RNO
FROM #Table1)A
WHERE RNO = 1
with cte as
(
select *,rank() over ( partition by id order by Newid()) as rn from #c
)
select id,code,age from cte where rn=1
To select different sets each time, use checksum(newid()) in the order by clause.
Query
;with cte as(
select *, rn = row_number() over(
partition by ID
order by abs(checksum(newid())) % 15
)
from [your_table_name]
)
select * from cte
where rn = 1;

Order result according to result of a function

I use below query but occur error that
invalid column name money
select * from (SELECT ROW_NUMBER() OVER (order by money desc) as row,
ChargeLog.customerCode,(select taraz from getCustomerMoney(ChargeLog.customerCode)) as money
from ChargeLog
)tblTemp
WHERE row between (1 - 1) * 20 + 1 AND 1*20
Try this:
WITH T AS
( SELECT ChargeLog.customerCode,
(select taraz from getCustomerMoney(ChargeLog.customerCode)) as money
from ChargeLog
), T2 AS
(
SELECT ROW_NUMBER() OVER (order by money desc) as row,
customerCode,
Money
FROM T
)
SELECT * FROM T2 WHERE row between (1 - 1) * 20 + 1 AND 1*20

Resources