SQL query to find the entries corresponding to the maximum count of each type - sql

I have a table X in Postgres with the following entries
A B C
2 3 1
3 3 1
0 4 1
1 4 1
2 4 1
3 4 1
0 5 1
1 5 1
2 5 1
3 5 1
0 2 2
1 2 3
I would like to find out the entries having maximum of Column C for every kind of A and B i.e (group by B) with the most efficient query possible and return corresponding A and B.
Expected Output:
A B C
1 2 3
2 3 1
0 4 1
0 5 1
Please help me with this problem . Thank you

demo: db<>fiddle
Using DISTINCT ON:
SELECT DISTINCT ON (B)
A, B, C
FROM
my_table
ORDER BY B, C DESC, A
DISTINCT ON gives you exactly the first row for an ordered group. In this case B is grouped.
After ordering B (which is necessary): We first order the maximum C (with DESC) to the top of each group. Then (if there are tied MAX(C) values) we order the A to get the minimum A to the top.

Seems like it is a greatest n per group problem:
WITH cte AS (
SELECT *, RANK() OVER (PARTITION BY B ORDER BY C DESC, A ASC) AS rnk
FROM t
)
SELECT *
FROM cte
WHERE rnk = 1
You're not clear which A needs to be considered, the above returns the row with smallest A.

itseems to me you need max()
select A,B, max(c) from table_name
group by A,B

this will work:
select * from (SELECT t.*,
rank() OVER (PARTITION BY A,B order by C) rank
FROM tablename t)
where rank=1 ;

Related

How to select the last value which is not null?

I have the following table:
id a b
1 1 kate
1 4 null
1 3 paul
1 3 paul
1 2 lola
2 1 kim
2 9 null
2 2 null
In result it should be this:
1 3 paul
2 1 kim
I want to get the last a where b is not null. Something like:
select b
from (select,b
row_num() over (partition by id order by a desc) as num) as f
where num = 1
But this way I get a null value, because to the last a = 4 corresponds to b IS NULL. Maybe there is a way to rewrite ffill method from pandas?
Assuming:
a is defined NOT NULL.
You want the row with the greatest a where b IS NOT NULL - per id.
SELECT DISTINCT ON (id) *
FROM tbl
WHERE b IS NOT NULL
ORDER BY id, a DESC;
db<>fiddle here
Detailed explanation:
Select first row in each GROUP BY group?
Try:
select id, a, b
from (select id, a, b,
row_num() over (partition by id order by a desc nulls last) as num
from unnamedTable) t
where num = 1
Or, if that isn't right, try it with nulls first. I can never remember which way it works with desc.
If you aren't guaranteed to have at least one non-null per id then you'll want to move nulls to the bottom of the list rather than filtering those rows out entirely.
select id, a, b
from (
select id, a, b,
row_number() over (
partition by id
order by case when b is not null then 0 else 1 end, a desc
) as num
) as f
where num = 1
You can wrap this around a cte and join it back to the main table if you wish to keep the original columns as is, but looking at your expected output and logic, this should do it. Having said that, row_number() based approach might be a tad faster.
select distinct
id,
max(a) over (partition by id) as a,
first_value(b) over (partition by id order by a desc) as b
from tbl
where b is not null;

Can you rearrange rows in sql tables accodring to a custom logic?

So I've been trying to change the order of rows according to my own logic.
Let's say I have a set of numbers from 1 to 4. If the rows have n entries of different values from 1 to 4 and I want to rearrange all the rows such that I have only rows with 4 at the top followed by a grouped combination of two 2's and a 1, followed by the 3's.
How can it be done using Sql server?
ID ROWS --> ID NEW ORDER
-- ---- -- ---------
A 1 G 4
B 1 G 4
C 2 G 4
C 2 G 4
D 2 C 2
D 2 C 2
E 2 A 1
E 2 E 2
F 3 E 2
F 3 B 1
F 3 D 2
G 4 D 2
G 4 F 3
G 4 F 3
G 4 F 3
Code till now:
SELECT * FROM table
ORDER BY
CASE
WHEN ROW = 4 THEN '1'
WHEN ROW = 1 THEN '2'
WHEN ROW = 2 THEN '3'
WHEN ROW = 3 THEN '4'
END ASC
Assuming ROWS is exactly the number of rows with a paticular ID,
order the rows first by a group according to ROWS interval (4),(1..2), (all the rest) then within the second group row_number() sequences of IDs having ROWS = 1 and 2 independently. Within the same sequence number order by ROWS reverse order.
select ID, ROWS
from (
select *
, case when ROWS = 4 then 1
when ROWS between 1 and 2 then 2
else 3 end grp1
, row_number() over(partition by ROWS order by ROWS) - row_number() over(partition by ROWS, ID order by ID) pos2
from yourtable) t
order by grp1, case ROWS when 1 then pos2 else pos2/2 end, -ROWS, ID
If you want you can try doing it using order by clause. You can use your logic to sort values accordingly. Default order by ASC. So i have tried below query with order by if this gives you some idea of doing it:
select id from test order by case when id%2 = 0 then id end desc
Will give;
ID
8
6
4
5
So you can try ordering with some logic inside.

SQL - after sorting, return only rows with certain consecutive values in a column

I have columns name, timestamp, doing. I've already sorted by name, then by timestamp, and I expect that moving down the doing column within a group with the same name looks like A, A, A, B, B, A, A, ... - alternating series of A and B. I need to get only the rows which comprise the first B row after a transition from A to B within a group with the same name.
name timestamp doing
1 1 A
1 2 A
1 3 B
1 4 B
1 5 A
2 2 B
2 4 A
2 6 B
2 8 A
I would like to return
name timestamp doing
1 3 B
2 6 B
But not
2 2 B
because it is not a transition from A to B within name = 2
I think you just want lag():
select t.*
from (select t.*,
lag(doing) over (partition by name order by timestamp) as prev_doing
from t
) t
where prev_doing = 'A' and doing = 'B';

SQL: create a query with a column identifying each tuple of values

I've been trying to find a solution for this SQL query:
|A| |B| |Output|
===========================
1 A 1
1 A 1
1 B 2
1 C 3
2 C 1
2 D 2
2 F 3
2 H 4
3 D 1
3 D 1
3 I 2
As you can see, I want to create a column (output) that identifies, not counts or sums, the occurrence of each (A,B) tuple, without removing repeated occurences.
How would you do that?
Thanks in advance
Look up SQL Server Built-in DENSE_RANK() function.
SELECT *
,DENSE_RANK() OVER (PARTITION BY [A] ORDER BY [B] ASC) AS [OutPut]
FROM TableName
I think you want dense_rank():
select t.*,
dense_rank() over (partition by a order by b)
from table t;

SQL: How to count instances of Column A in Column B

I have a table with 2 columns A, and B that represent a connection graph between the two.
A B
1 3
2 5
4 2
3 5
2 3
I need to find how many instances of column A occur in column B (including 0)
So for the example above I would need the result set
A OccurencesInB
1 0
2 1
3 2
4 0
The best I have so far is
SELECT B, COUNT(*) AS TABLE_COUNT
FROM TABLE
GROUP BY B
ORDER BY TABLE_COUNT DESC
This does not find the instances of A that do not occur in B, which is crucial.
Any assistance will be greatly appreciated!
Use a correlated sub-query:
SELECT A,
TABLE_COUNT = (SELECT COUNT(*)
FROM TableName t2
WHERE t2.B = t1.A)
FROM TableName t1
GROUP BY A
ORDER BY TABLE_COUNT DESC, A
Result:
A TABLE_COUNT
3 2
2 1
1 0
4 0