how to select one row from several rows with minimum value - sql

The question based on SQL query to select distinct row with minimum value.
Consider the table:
id game point
1 x 1
1 y 10
1 z 1
2 x 2
2 y 5
2 z 8
Using suggested answers from mentioned question (select the ids that have the minimum value in the point column, grouped by game) we obtain
id game point
1 x 1
1 z 1
2 x 2
The question is how to obtain answer with single output for each ID. Both outputs
id game point
1 x 1
2 x 2
and
id game point
1 z 1
2 x 2
are acceptable.

Use row_number():
select t.*
from (select t.*,
row_number() over (partition by id order by point asc) as seqnum
from t
) t
where seqnum = 1;

We assume that all point entries are distinct(for each id and it's game so we can obtain the minimum of each id with it's game), Using a subquery and an inner join with two conditions would give you the result you,re waiting for.If it doesnt work with you I got another solution :
SELECT yt.*,
FROM Yourtable yt INNER JOIN
(
SELECT ID, MIN(point) MinPoint
FROM Yourtable
GROUP BY ID
) t ON yt.ID = t.ID AND yt.Record_Date = yt.MinDate

Related

Merge two tables and chain id fields in order

I'm looking for a way to merge two tables (or more) and modify/order their numeric id. To put it simply here is what I want to do schematically :
Table example 1 :
Id
Field
4
x
1
x
5
x
3
x
2
x
Table example 2 :
Id
Field
1
x
3
x
5
x
2
x
4
x
Expected result (modify table 1 as 1-2-3-4-5 and table 2 as 6-7-8-9-10 THEN order both id by asc)
Id
Field
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
x
10
x
I was aiming for a union tables nested in a select row_number() over (order by id) but I don't really know how to modify table 2 as 6-7-8-9-10 before
Try using this example:
SELECT id, Field FROM t1
UNION ALL
SELECT (SELECT MAX(id) FROM t1) + ROW_NUMBER() OVER (ORDER BY id) AS id, Field
FROM t2
ORDER BY id
fiddle

How to get first and last row of each island?

So I recently got excellent help on a problem. However, I need to get a little more precise, which hopefully is doable in SQL.
This was my last problem:
Select only rows that has a column changed from the rows before it, given an unique ID
Clarificiation:
The help I got in that problem was to give me the start of every Island. However, I want the start and stop of every Island instead.
My nuance is this:
personID | status | unixtime | column d | column e | column f
1 2 213214 x y z
1 2 213325 x y z
1 2 213326 x y z
1 2 213327 x y z
1 2 213328 x y z <-- I want this
1 3 214330 x y z <-- Any of this is OK
1 3 214331 x y z
1 3 214332 x y z <-- I want this or
1 2 324543 x y z <-- I want this
So instead of the start of the islands, I want the end of the island. If I get something in between it's totally ok, preferably it would be the end. But I really want what is the "right before" and "right after" the status changes, if this gives any meaning. This could be a specific status.
This query produces all rows that either end or start a partition (or both in case of a single-row partition):
SELECT *
FROM (
SELECT *
, lag(status) OVER w IS DISTINCT FROM status AS partition_start
, lead(status) OVER w IS DISTINCT FROM status AS partition_end
FROM tbl
WINDOW w AS (PARTITION BY personID ORDER BY unixtime)
) sub
WHERE (partition_start OR partition_end)
ORDER BY personID, unixtime;
db<>fiddle here
Note that with PARTITION BY personID, rows with a different personID do not interrupt the "island". I added rows to your test case in the fiddle to demonstrate the effect.
If your requirements are different, you'll have to define how.
select t.*
from (select t.*,
case when status <> lag(status,1,NULL) over(partition by personID order by unixtime)
then 1
when lag(status,1,NULL) over(partition by personID order by unixtime) is null
then 1
else 0 end as start_status,
case when status <> lead(status,1,NULL) over(partition by personID order by unixtime)
then 1
when lead(status,1,NULL) over(partition by personID order by unixtime) is null
then 1
else 0 end as end_status
from mytable t
) t
where end_status = 1
--or start_status = 1 -- uncomment this line if you want start statuses as well

sql - select single ID for each group with the lowest value

Consider the following table:
ID GroupId Rank
1 1 1
2 1 2
3 1 1
4 2 10
5 2 1
6 3 1
7 4 5
I need an sql (for MS-SQL) select query selecting a single Id for each group with the lowest rank. Each group needs to only return a single ID, even if there are two with the same rank (as 1 and 2 do in the above table). I've tried to select the min value, but the requirement that only one be returned, and the value to be returned is the ID column, is throwing me.
Does anyone know how to do this?
Use row_number():
select t.*
from (select t.*,
row_number() over (partition by groupid order by rank) as seqnum
from t
) t
where seqnum = 1;

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

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 ;

PLSQL or SSRS, How to select having all values in a group?

I have a table like this.
ID NAME VALUE
______________
1 A X
2 A Y
3 A Z
4 B X
5 B Y
6 C X
7 C Z
8 D Z
9 E X
And the query:
SELECT * FROM TABLE1 T WHERE T.VALUE IN (X,Z)
This query gives me
ID NAME VALUE
______________
1 A X
3 A Z
4 B X
6 C X
7 C Z
8 D Z
9 E X
But i want to see all values of names which have all params. So, only A and C have both X and Z values, and my desired result is:
ID NAME VALUE
______________
1 A X
2 A Y
3 A Z
6 C X
7 C Z
How can I get the desired result? No matter with sql or with reporting service. Maybe "GROUP BY ..... HAVING" clause will help, but I'm not sure.
By the way I dont know how many params will be in the list.
I realy appreciate any help.
The standard approach would be something like
SELECT id, name, value
FROM table1 a
WHERE name IN (SELECT name
FROM table1 b
WHERE b.value in (x,y)
GROUP BY name
HAVING COUNT(distinct value) = 2)
That would require that you determine how many values are in the list so that you can use a 2 in the HAVING clause if there are 2 elements, a 5 if there are 5 elements, etc. You could also use analytic functions
SELECT id, name, value
FROM (SELECT id,
name,
value,
count(distinct value) over (partition by name) cnt
FROM table1 t1
WHERE t1.value in (x,y))
WHERE cnt = 2
I prefer to structure these "sets within sets" of queries as an aggregatino. I find this is the most flexible approach:
select t.*
from t
where t.name in (select name
from t
group by name
having sum(case when value = 'X' then 1 else 0 end) > 0 and
sum9case when value = 'Y' then 1 else 0 end) > 0
)
The subquery for the in finds all names that have at least one X value and one Y value. Using the same logic, it is easy to adjust for other conditions (X and Y and Z,; X and Y but not Z and so on). The outer query just returns all the rows instead of the names.