SQL Take Max and Include Non-Group By COLS - sql

TABLE1
ID STUDENT SCORE TIME
A 1 9 1
A 1 8 2
B 1 0 1
B 1 10 2
B 1 7 3
C 2 5 1
C 2 1 2
C 2 0 3
D 3 1 1
E 3 0 1
D 3 4 2
D 3 4 3
E 3 9 2
F 4 6 1
G 4 6 1
WANT
ID STUDENT MAXSCORE TIME
A 1 9 1
B 1 10 2
B 1 7 3
C 2 5 1
C 2 1 2
C 2 0 3
D 3 1 1
E 3 9 2
D 3 4 3
F 4 6 1
I have TABLE1 and wish for WANT which does this:
for every STUDENT/TIME, select the row with the MAX(SCORE)
I try this::
select ID, STUDENT, MAX(SCORE) AS MAXSCORE, TIME
from TABLE1
group by STUDENT, TIME
But amn't able to include ID

First get the max score by student/time, then join back to the original table.
WITH dat
AS
(
SELECT student, time, MAX(score) AS max_score
FROM TABLE1
GROUP BY student, time
)
SELECT DISTINCT t.id, t.student, d.max_score, t.time
FROM TABLE1 t
INNER JOIN dat d
ON t.student = d.student AND t.time = d.time AND t.score = d.max_score;

If the RDBMS supports window functions, then
with cte as (
select id,
student,
score,
time,
row_number() over (partition by student, time order by score desc) as rn
from table1)
select id, student, score, time
from cte
where rn = 1;

Related

Find records on group level which are connected to all other record within the group

I have a scenario where I have to find IDs within each group which are connected to all other IDs in the same group. So basically we have to treat each group separately.
In the table below, the group A has 3 IDs 1, 2 and 3. 1 is connected to both 2 and 3, 2 is connected to both 1 and 3, but 3 is not connected to 1 and 2. So 1 and 2 should be output from group A. Similarly in group B only 5 is connected to all other IDs namely 4 and 6 within group B, so 5 should be output. Similarly from group C, that should be 8, and from group D no records should be output.
So the output of the select statement should be 1, 2, 5, 8.
GRP
ID
CONNECTED_TO
A
1
2
A
1
3
A
2
3
A
2
1
A
3
5
B
4
5
B
5
4
B
5
6
B
6
4
C
7
21
C
7
25
C
8
7
D
9
31
D
10
35
D
11
37
I was able to do this if group level was not required, by below SQL:
SELECT ID FROM <table>
where CONNECTED_TO in (select ID from <table>)
group by ID
having count(*) = <number of records - 1>
But not able to find correct SQL for my scenario. Any help is appreciated.
You may use count and count(distinct) functions as the following:
select id
from tbl T
where connected_to in
(
select id from tbl T2
where T2.grp = T.grp
)
group by grp, id
having count(connected_to) =
(
select count(distinct D.id) - 1
from tbl D
where T.grp = D.grp
)
When count(connected_to) group by grp, id equals to the count(distinct id) - 1 with the same grp, this means that the ID is connected to all other IDs.

Select commonly chosen desires collage by students after first 5 rows each group

With subquery I need to select after first five rows for each group of id_student and must common values of id_desireCollage between id_student.
More explain : select common collages for each student desires after his five chosen desires
ID
id_desireCollage
id_student
1
1
1
2
2
1
3
3
1
4
4
1
5
5
1
6
8
1
7
9
1
8
7
1
9
2
2
10
12
2
11
1
2
12
3
2
13
6
2
14
5
2
15
8
2
16
9
2
17
7
2
18
4
3
19
3
3
20
2
3
21
1
3
22
8
3
23
9
3
24
7
3
25
5
3
Something like
select id_desireCollage
from
(select *
from desires ds
where ds.id_desireCollage = desires.id_desireCollage)
group by (id_student)
having count(*) > 5
Expected result is:
id_desireCollage
7
9
Try the following:
select id_desireCollage
from
(
select d.*,
row_number() over (partition by id_student order by ID) as rn
from desires d
) T
where rn > 5
group by id_desireCollage
order by count(*) desc
fetch first 1 row with ties
If you don't want to use the row number function (as you commented), you may try the following - supposing there are no gaps in the ID column:
select id_desireCollage
from desires d
where id >=
(
select min(id)+5
from desires t
where t.id_student = d.id_student
)
group by id_desireCollage
order by count(*) desc
fetch first 1 row with ties
See demo
As suggested by #MatBailie, if you meant by common, that all students have selected the id_desireCollage value then you could use the following:
select id_desireCollage
from desires d
where id >=
(
select min(id)+5
from desires t
where t.id_student = d.id_student
)
group by id_desireCollage
having count(*)=
(
select count(distinct id_student)
from desires
)

Select quantity on a 1st table based on a total quantity the 2nd table

Table 1
ID
Grp
Qty
1
A
5
2
A
4
3
B
5
4
B
3
5
B
2
6
C
14
7
D
1
8
D
1
9
E
2
10
E
2
11
E
1
12
E
1
Table 2
ID
Grp
Qty
1
A
7
2
B
9
3
C
13
4
D
1
5
E
4
Select/Output
ID
Grp
Qty
1
A
0
2
A
2
3
B
0
4
B
0
5
B
1
6
C
1
7
D
0
8
D
1
9
E
0
10
E
0
11
E
1
12
E
1
I want to select a row on a 1st table with a specific quantity based on the total quantity of the 2nd table. The result is on the 3rd table. Please see sample tables above, I really appreciate a help, thank you so much and sorry it was my first time asking a question here.
I have tried this code on both 2 tables
WITH tbl AS(
SELECT ID,
Qty,
Grp,
ROW_NUMBER() OVER (PARTITION BY Grp)AS Rown,
SUM(Qty) OVER (PARTITION BY Grp)AS Total
FROM Table1
)
SELECT * FROM tbl WHERE Rown = 1
But I am not able to select the specific rows on Table 1 because it only select the 1st row and total the quantity. Every row on table 1 has its own quantity.
You could use a cumulative windowed aggregates and then a CASE expression to achieve this:
--Saple Data
WITH Table1 AS(
SELECT *
FROM (VALUES(1,'A',5),
(2,'A',4),
(3,'B',5),
(4,'B',3),
(5,'B',2),
(6,'C',14))V(ID,Grp,Qty)),
Table2 AS(
SELECT *
FROM (VALUES(1,'A',7),
(2,'B',9),
(3,'C',13))V(ID,Grp,Qty)),
--Solution
CTE AS(
SELECT T1.ID,
T1.Grp,
T1.Qty,
SUM(T1.Qty) OVER (PARTITION BY T1.Grp ORDER BY T1.Id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS RunningQty,
T2.Qty AS T2Qty
FROM Table1 T1
JOIN Table2 T2 ON T1.Grp = T2.Grp)
SELECT C.ID,
C.Grp,
CASE WHEN C.RunningQty <= C.T2Qty THEN C.Qty
ELSE C.T2Qty - LAG(C.RunningQty,1,0) OVER (PARTITION BY C.Grp ORDER BY C.ID)
END AS Qty
FROM CTE C;

Update a column if a row is not a duplicate, or a row's ID isn't a certain number in SQL SSMS

I have a table, and I would like the following update command to set isExcluded = 1 to all rows where PhoneID and PhoneName are not duplicates and all rows where the ID doesn't not have the smallest number from a selected PhoneID if those rows do not have a duplicate PhoneID and PhoneName (i.e.: since all rows with PhoneID = 2 are not duplicates, the row containing PhoneName = b has the smallest ID, since it's ID = 3. Therefore, all rows with PhoneID = 2 and ID > 3 will have their IsExcluded set to 1).
ID
PhoneID
PhoneName
isExcluded
1
1
a
0
2
1
a
0
3
2
b
0
4
2
c
0
5
2
d
0
6
2
e
0
7
3
c
0
8
3
c
0
9
3
d
0
10
3
d
0
Here's my SQL script that I wrote. It only seems to get the non-duplicates only.
WITH Duplicates AS
(
SELECT
ID, PhoneID, PhoneName, isExcluded,
(ROW_NUMBER() OVER (PARTITION BY PhoneName, PhoneID ORDER BY ID)) AS RowNum
FROM
Phones
)
UPDATE Phones
SET isExcluded = 1
FROM Duplicates d
WHERE (
d.PhoneID = Phones.PhoneID
AND d.PhoneName = Phones.PhoneName
AND d.RowNum =< 1);
SELECT * FROM Phones;
This table should be the result of my command.
ID
PhoneID
PhoneName
isExcluded
1
1
a
0
2
1
a
0
3
2
b
0
4
2
c
1
5
2
d
1
6
2
e
1
7
3
c
0
8
3
c
0
9
3
d
1
10
3
d
1
This looks to be a variation of a gaps and islands problem, which you can solve by first grouping the partitions and then using an updatable CTE to assign the isExcluded value
with gp as (
select *,
Row_Number() over(order by id)
- Row_Number() over(partition by phoneid, phonename order by id) gp
from t
), p as (
select *,
case when Min(gp) over(partition by phoneid) <gp then 1 end IsEx
from gp
)
update p set isExcluded = isEx
where IsEx = 1
See working DB<>Fiddle

How to implement sequence in the SQL query

I have a query in SQL Server which gives me the count of policies according to AGE and SEX as mentioned below.
SELECT
PLYMMRAGE as AGE,
MMRSEX as SEX,
COUNT(PLYNO) AS POLICYCOUNT
FROM
ADMGMPLYMSR
GROUP BY
PLYMMRAGE, MMRSEX
ORDER BY
MMRSEX DESC, PLYMMRAGE
Output of this query is:
AGE SEX POLICYCOUNT
------------------------
2 M 10
4 M 9
5 M 6
8 M 0
1 F 4
2 F 6
4 F 0
But I want that even if the age is not present the row should display for all ages with policy count as 0 till age 10.
AGE SEX POLICYCOUNT
-------------------------
1 M 0
2 M 10
3 M 0
4 M 9
5 M 6
6 M 0
7 M 0
8 M 0
9 M 0
10 M 0
1 F 4
2 F 6
4 F 0
and so on.
How can I insert the data with zero count if the age for that row is not present? Even if using procedure is fine
You can use a LEFT JOIN and coalesce together
with ADMGMPLYMSR( PLYMMRAGE, MMRSEX, PLYNO ) as
(
select 2,'M',10 union all
select 4,'M', 9 union all
select 5,'M', 6 union all
select 8,'M', 0 union all
select 1,'M', 4 union all
select 2,'M', 6 union all
select 4,'M', 0
), t AS (
SELECT 1 AS n
UNION ALL
SELECT n+1 FROM t WHERE n+1<=10
)
SELECT COALESCE(PLYMMRAGE,n) as AGE, COALESCE(MMRSEX,'M') as SEX,
COUNT(PLYNO) AS POLICYCOUNT
FROM t
LEFT JOIN ADMGMPLYMSR ON PLYMMRAGE = n
GROUP BY coalesce(PLYMMRAGE,n), MMRSEX
ORDER BY coalesce(MMRSEX,'M') DESC, coalesce(PLYMMRAGE,n);
Demo