SQL rank calculation by row - sql

I have a table
Name
count
rank
A
2
1
A
4
2
A
7
3
I am trying to calculate new column D for the count with rank
for rank 1, count = 2
for rank 2, count = 4-2 =2
for rank 3, count = 7-2 -4 =1
The expected result should be
Name
count
rank
D
A
2
1
2
A
4
2
2
A
7
3
1
I am trying to use patrion by but it's not working

Use SUM() window function:
SELECT *,
2 * count - SUM(count) OVER (ORDER BY rank) D
FROM tablename;
See the demo.

Related

SUM a column in SQL, based on DISTINCT values in another column, GROUP BY a third column

I'd appreciate some help on the following SQL problem:
I have a table of 3 columns:
ID Group Value
1 1 5
1 1 5
1 2 10
1 2 10
1 3 20
2 1 5
2 1 5
2 1 5
2 2 10
2 2 10
3 1 5
3 2 10
3 2 10
3 2 10
3 4 50
I need to group by ID, and I would like to SUM the values based on DISTINCT values in Group. So the value for a group is only accounted for once even though it may appear multiple for times for a particular ID.
So for IDs 1, 2 and 3, it should return 35, 15 and 65, respectively.
ID SUM
1 35
2 15
3 65
Note that each Group doesn't necessarily have a unique value
Thanks
the CTE will remove all duplicates, so if there a sdiffrenet values for ID and Group, it will be counted.
The next SELECT wil "GROUP By" ID
For Pstgres you would get
WITH CTE as
(SELECT DISTINCT "ID", "Group", "Value" FROM tablA
)
SELECT "ID", SUM("Value") FROM CTE GROUP BY "ID"
ORDER BY "ID"
ID | sum
-: | --:
1 | 35
2 | 15
3 | 65
db<>fiddle here
Given what we know at the moment this is what I'm thinking...
The CTE/Inline view eliminate duplicates before the sum occurs.
WITH CTE AS (SELECT DISTINCT ID, Group, Value FROM TableName)
SELECT ID, Sum(Value)
FROM CTE
GROUP BY ID
or
SELECT ID, Sum(Value)
FROM (SELECT DISTINCT * FROM TableName) CTE
GROUP BY ID

Row Number with specific window size

I want to group records by row numbers.
Like from row 1-3 in group 1 , 4-6 in group 2 , 7-9 in group 3 and so on.
Suppose below is the table structure:
Row NumberDataValue
1 A 10
2 A 5
3 A 1
4 A 33
5 A 2
6 A 127
1 B 1
2 B 0
3 B 7
4 B 7
5 B 5
6 B 8
7 B 1
8 B 0
I want a output like this:
GroupValue
1 10
1 5
1 1
2 33
2 2
2 127
1 1
1 0
1 7
2 7
2 5
2 8
3 1
3 0
I am using Oracle 11G.
I can achieve this using PL/SQL. But I have to use SQL only. As I have to use this query in a reporting tool.
If this is a duplicate question please provide the link of the answered question.
Subtract 1 from the column "RowNumber" and divide by 3.
Then use TRUNC() to get the integer part:
SELECT TRUNC(("RowNumber" - 1) / 3) + 1 "Group",
"Value"
FROM tablename
See the demo.
I would assume the name of the first column is ordering.
You can do:
select
1 + trunc(row_number() over(partition by data order by ordering) - 1) / 3,
value
from t
What you show looks like the output from something like this:
select ceil(rn/3) as grp, value
from your_table
order by rn;
Note that "row number" and "group" are reserved words/phrases which should not be used as column names. I used rn and grp instead.
I think the ceiling function is the simplest way to arrive at what you want. If you want to base it on the RowNumber column:
select ceil( RowNumber / 3.0) as grouping
If you want to calculate it yourself using row_number():
select ceil( row_number() over (order by RowNumber) / 3.0 ) as grouping

SQL - group for every 2 records

Original Table:
id rank
A 1
B 1
D 2
E 2
G 3
H 3
I 4
J 5
K 6
L 6
M 7
Would like to add one more group column - the value will be + 1 every 2 record:
id rank group
A 1 1
B 1 1
D 2 1
E 2 1
G 3 2
H 3 2
I 4 2
J 5 3
K 6 3
L 6 3
M 7 4
What I can think is only able to hardcode a "case when" condition for ranking. Since the table could be large, is there another function that can group the record dynamically?
Case when rank >0 and rank <=2 then 1 When rank >2 and rank <=4 then 2 When rank >4 and rank <=6 then 3 end group ....
Using ceil() function would be a direct option after dividing rate column by 2 :
SELECT id, rank, ceil( rank / 2 ) as "group"
FROM tab;
Btw, I replaced group with "group" since it is a reserved keyword
This is achievable using dense_rank()
select dense_rank() over (partition by rank % 2 order by id) as grouping, rank
from tableA
order by rank

Is there a way to group this data?

Data Looks like -
1
2
3
1
2
2
2
3
1
5
4
1
2
So whenever there is a 1, it marks the beginning of a group which includes all the elements until it hits the next 1. So here,
1 2 3 - group 1
1 2 2 2 3 - group 2
and so on..
What would be the SQL query to show the average for every such group.
I could not figure out how to group them without using for loops or PLSQL code.
Result should look like two columns, one with the actual data and col 2 with the average value-
1 - avg value of 1,2 3
2
3
1 - avg value of 1,2,2,2,3
2
2
2
3
1 - avg value of 1,5,4
5
4
1 - avg value of 1,2
2
SQL tables represent unordered sets. There is no ordering, unless a column specifies the ordering. Let me assume that you have such a column.
You can identify the groups using a cumulative sum:
select t.*,
sum(case when t.col = 1 then 1 else 0 end) over (order by ?) as grp
from t;
? is the column that specifies the ordering.
You can then calculate the average using aggregation:
select grp, avg(col)
from (select t.*,
sum(case when t.col = 1 then 1 else 0 end) over (order by ?) as grp
from t
) t
group by grp;

SQL Server GROUP BY COUNT Consecutive Rows Only

I have a table called DATA on Microsoft SQL Server 2008 R2 with three non-nullable integer fields: ID, Sequence, and Value. Sequence values with the same ID will be consecutive, but can start with any value. I need a query that will return a count of consecutive rows with the same ID and Value.
For example, let's say I have the following data:
ID Sequence Value
-- -------- -----
1 1 1
5 1 100
5 2 200
5 3 200
5 4 100
10 10 10
I want the following result:
ID Start Value Count
-- ----- ----- -----
1 1 1 1
5 1 100 1
5 2 200 2
5 4 100 1
10 10 10 1
I tried
SELECT ID, MIN([Sequence]) AS Start, Value, COUNT(*) AS [Count]
FROM DATA
GROUP BY ID, Value
ORDER BY ID, Start
but that gives
ID Start Value Count
-- ----- ----- -----
1 1 1 1
5 1 100 2
5 2 200 2
10 10 10 1
which groups all rows with the same values, not just consecutive rows.
Any ideas? From what I've seen, I believe I have to left join the table with itself on consecutive rows using ROW_NUMBER(), but I am not sure exactly how to get counts from that.
Thanks in advance.
You can use Sequence - ROW_NUMBER() OVER (ORDER BY ID, Val, Sequence) AS g to create a group:
SELECT
ID,
MIN(Sequence) AS Sequence,
Val,
COUNT(*) AS cnt
FROM
(
SELECT
ID,
Sequence,
Sequence - ROW_NUMBER() OVER (ORDER BY ID, Val, Sequence) AS g,
Val
FROM
yourtable
) AS s
GROUP BY
ID, Val, g
Please see a fiddle here.