select max value in each 5 rows - sql-server

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

Related

Setting a column with a Page value for every million rows

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.

sequence Rank in query

I would like to get sequence number in mssql. Please see below.
There is a table.
UserID Score TeamID
------------------------------
1 100 1
2 200 1
3 500 2
4 600 2
5 700 2
6 1000 3
I would like to sort by total score group by team. see below
RankID UserID Score TeamID TotalScore
-----------------------------------------------------------
1 3 500 2 1800
1 4 600 2 1800
1 5 700 2 1800
2 6 1000 3 1000
3 1 100 1 300
3 2 200 1 300
I want to code only one sql query. Help me someone how can I do this? Thanks.
This should work:
;WITH TotalScore AS (
SELECT UserID, Score, TeamID,
SUM(Score) OVER (PARTITION BY TeamID) AS TotalScore
FROM mytable
)
SELECT DENSE_RANK() OVER (ORDER BY TotalScore DESC) AS RankID,
UserID, Score, TeamID, TotalScore
FROM TotalScore
ORDER BY TotalScore DESC, Score
The Common Table Expression used calculates the total score per TeamID using windowed version of SUM. Using DENSE_RANK together with this calculated field we can easily generate the required RankID.
You can try this
SELECT
RANK() OVER(ORDER BY i.TotalScore DESC) AS RankID
,A.*
FROM
(
SELECT
UserID
,Score
,TeamID
,(SELECT SUM(Score) FROM yourTable tb2 WHERE tb2.TeamID = tb1.TeamID) AS TotalScore
FROM yourTable tb1
) A
ORDER BY A.TotalScore DESC
Have a Try with below,
Select DENSE_RANK() over(Order by (Select Sum(Score) from #tablename V where V.TeamID=T.TeamID ) desc )RankID
,*,
Sum(Score) over(Partition by TeamID) TotalScore from #tablename T
order by DENSE_RANK() over(Order by (Select Sum(Score) from #tablename V where V.TeamID=T.TeamID ) desc )
Dense Rank in the 'Order by' to sort the results by RANK Id and the same is used in Select statement, Subquery in the Dense Rank will rank based on the sum(Score) for a TeamID

How do I achieve addition of each rows in T-SQL?

I have my data which may be around 50 records for each address:
Id AddressId Income Expense Revenue
----------------------------------------
1 1 100 200 300
2 1 150 20 200
3 1 160 80 800
4 1 50 90 200
5 1 600 700 500
Now I need my data in the following format:
Ids Count Income Expense Revenue
---------------------------------------
1 1 100 200 300
1,2 2 250 220 500
1,2,3 3 410 300 1300
1,2,3,4 4 460 390 1500
1,2,3,4,5 5 1060 1090 2000
Every row is being added one after another.
For example:
The Ids 1,2 is a sum of Id 1 and 2
The Ids 1,2,3 is a sum of Id 1 and 2 and 3 and so on
I don't need the Ids column, the only thing I need is the sum
You could use STUFF, ROW_NUMBER() OVER(), and SUM() OVER() like this
DECLARE #SampleData AS TABLE
(
Id int,
AddressId int,
Income int,
Expense int,
Revenue int
)
INSERT INTO #SampleData
VALUES
( 1, 1, 100, 200, 300),
( 2, 1, 150, 20 , 200),
( 3, 1, 160, 80 , 800),
( 4, 1, 50 , 90 , 200),
( 5, 1, 600, 700, 500)
SELECT
STUFF(
(
SELECT ',' + CAST(sd1.Id AS varchar(10))
FROM #SampleData sd1
WHERE sd1.AddressId = sd.AddressId AND sd1.Id <= sd.Id
FOR XML PATH('')
),
1,1,'') AS Ids,
Row_number() OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Count,
sum(sd.Income) OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Income,
sum(sd.Expense) OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Expense,
sum(sd.Revenue) OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Revenue
FROM #SampleData sd
ORDER BY sd.AddressId, sd.Id
Demo link: http://rextester.com/HRIWH92029
Note: The last revenue should be 2000 instead of 1600
If you're using SQL server 2012 and above,
please use below query for the sum up the previous rows
Select ID,
count(*) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row) as[Count],
sum(Income) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row) Income,
sum(Expense) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row)Expense,
sum(Revenue) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row) Revenue from TableName
If you're using SQL server 2008 and below, please use below query for the sum up the previous rows.
Select ID, (select count(*) from Tablename A where A.Id<=Tablename.ID)[Count],
(select sum(Income) from Tablename A where A.Id<=Tablename.ID) Income, (select
sum(Expense) from Tablename A where A.Id<=Tablename.ID) Expense, (select
sum(Revenue) from Tablename A where A.Id<=Tablename.ID) Revenue from Tablename

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;

how to fetch record monthly total in select query in sql server 2005

I am having following output of query
Query:
SELECT DATENAME(mm, date) [Month], sum(braekTime) [TotalBreakTime],
sum(DATEPART(hh,totalTime) * 60 + DATEPART(mi,totalTime) + DATEPART(ss,totalTime) * 0.017) [Minute],firstName
FROM employeeAttendance,employee
where FK_employeeId = employee.employeeId
GROUP BY DATENAME(mm, date),firstName
ORDER BY [Month]
but I want each n every month record with null/ 0 value
like June and July record is not available then it should display like following
Month TotalBreakTime Minute firstName
----- -------------- ------ ---------
January 0 0 NULL
February 0 0 NULL
March 0 0 NULL
April 0 0 NULL
May 50 1015.000 foramaa
June 0 0 NULL
July 0 0 NULL
.... Like till Dec
You should create a virtual table or subquery for the months, and left join it to the totals query.
eg
select * from
(
select number, datename(m,DATEADD(m, number-1, 0)) as monthname
from master..spt_values
where type='p' and number between 1 and 12
) months
left join
(your totals query) totals
on months.monthname = totals.month
try this:
;with cte as(
select 1 as rn union all select 2 union all select 3),
cte1 as (select ROW_NUMBER() over(order by c1.rn) as row_num
from cte cross join cte c1 cross join cte c2)
select * from cte1
left join
(SELECT DATENAME(mm, date) [Month],
sum(braekTime) [TotalBreakTime],
sum(DATEPART(hh,totalTime) * 60 + DATEPART(mi,totalTime) + DATEPART(ss,totalTime) * 0.017) [Minute],
firstName
FROM employeeAttendance join employee
on FK_employeeId = employee.employeeId
GROUP BY DATENAME(mm, date),firstName
ORDER BY [Month])B
on B.[Month]=DateName( month , DateAdd( month ,cte1.row_num , 0 ) - 1 )
and cte1.row_num <=12

Resources