Get only rows where data is the max value - sql

I have a table like this:
treatment | patient_id
3 | 1
3 | 1
3 | 1
2 | 1
2 | 1
1 | 1
2 | 2
2 | 2
1 | 2
I need to get only rows on max(treatment) like this:
treatment | patient_id
3 | 1
3 | 1
3 | 1
2 | 2
2 | 2
The patient_id 1 the max(treatment) is 3
The patient_id 2 the max(treatment) is 2

You can for example join on the aggregated table using the maximal value:
select t.*
from tmp t
inner join (
select max(a) max_a, b
from tmp
group by b
) it on t.a = it.max_a and t.b = it.b;
Here's the db fiddle.

Try this :
WITH list AS
( SELECT patient_id, max(treatment) AS treatment_max
FROM your_table
GROUP BY patient_id
)
SELECT *
FROM your_table AS t
INNER JOIN list AS l
ON t.patient_id = l.patient_id
AND t.treatment = l.treatment_max

You can use rank:
with u as
(select *, rank() over(partition by patient_id order by treatment desc) r
from table_name)
select treatment, patient_id
from u
where r = 1;
Fiddle

use corelated subquery
select t1.* from table_name t1
where t1.treatment=( select max(treatment) from table_name t2 where t1.patient_id=t2.patient_id
)

Related

single column value in multiple columns

ID|Class | Number
--+------+---------
1 | 1 | 58.2
2 | 1 | 85.4
3 | 2 | 28.2
4 | 2 | 55.4
The desired result would be:
Column1 |Number | Column2 | Number
--------+-------+---------+---------
1 | 58.2 | 2 |28.2
1 | 85.4 | 2 |55.4
What would be the required SQL?
You can user row_number() and aggregate:
select 1, max(case when seqnum % 2 = 1 then number end),
2, max(case when seqnum % 2 = 0 then number end)
from (select t.*,
row_number() over (partition by class order by id) as seqnum
from t
) t
group by ceiling(seqnum / 2.0);
The aggregation uses arithmetic to put pairs of rows for each class into one row.
try this
SELECT 1 AS Column1,t2.Number,2 AS Column2,t1.Number
FROM
(
SELECT *
FROM test11
) t2
INNER JOIN
(
SELECT *
FROM test11
) t1
ON t1.Class = t2.Class
WHERE t1.ID < t2.ID
ORDER BY t1.ID DESC
Demo in db<>fiddle

Create table with values from one column and another column without intersection

I have a table like so:
userid | clothesid
-------|-----------
1 | 1
1 | 3
2 | 1
2 | 4
2 | 5
What I want from this table is a table like so:
userid | clothesid
-------|-----------
1 | 4
1 | 5
2 | 3
How can I do this?
I've tried it with one entry as:
select distinct r.clothesid from table r where r.clothes not in (select r1.clothes from table r1 where r1.userid=1);
and this returns 4,5, but I'm not sure where to proceed from here
You can cross join the list of userids and the list of clothesid to generate all combinations, and then use not exists on the original table to identify the missing rows:
select u.userid, c.clothesid
from (select distinct userid from mytable) u
cross join (select distinct clothesid from mytable) c
where not exists(
select 1 from mytable t on t.userid = u.userid and t.clothesid = c.clothesid
)
I think you want:
select (case when t1.clothesid is not null then 2 else 1 end),
coalesce(t1.clothesid, t2.clothesid)
from (select t.*
from t
where t.userid = 1
) t1 full join
(select t.*
from t
where t.userid = 2
) t2
on t1.clothesid = t2.clothesid
where t1.clothesid is null or t2.clothesid is null;
Actually, I think I have a simpler solution:
select (case when min(t.userid) = 1 then 2 else 1 end), clothesid
from t
group by clothesid
having count(*) = 1;
Here is a db<>fiddle.
Left join all the combinations of userid and clothesid to the table and return only the unmatched rows:
select t1.userid, t2.clothesid
from (select distinct userid from tablename) t1
cross join (select distinct clothesid from tablename) t2
left join tablename t on t.userid = t1.userid and t.clothesid = t2.clothesid
where t.userid is null
Or with the operator EXCEPT:
select t1.userid, t2.clothesid
from (select distinct userid from tablename) t1
cross join (select distinct clothesid from tablename) t2
except
select userid, clothesid
from tablename
See the demo.
Results:
> userid | clothesid
> -----: | --------:
> 1 | 4
> 1 | 5
> 2 | 3

Sequence sum of row in SQL for a table

Consider below table.
ID UserCount
----------- -----------
1 2
2 3
3 5
How can i add the another column (SequenceUserCount) with UserCount adding sequentialy.
Expected result:
ID UserCount SequenceUserCount
----------- ----------- ------------------
1 2 2
2 3 5
3 5 10
You can do this:
;WITH CTE
AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY usercount) rownum
FROM #table1
)
SELECT
c1.id,
c1.usercount,
SequenceUserCount = (SELECT SUM(c2.usercount)
FROM cte c2
WHERE c2.rownum <= c1.rownum)
FROM CTE c1;
SQL Fiddle Demo
This will give you:
| ID | USERCOUNT | SequenceUserCount |
--------------------------------------
| 1 | 2 | 2 |
| 2 | 3 | 5 |
| 3 | 5 | 10 |
Or: You can use JOIN instead of a correlated subquery, like so:
;WITH CTE
AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY usercount) rownum
FROM #table1
)
SELECT
c1.id,
c1.usercount,
SequenceUserCount = SUM(c2.usercount)
FROM CTE c1
INNER JOIN CTE c2 ON c2.rownum <= c1.rownum
GROUP BY c1.id, c1.usercount;
try this
select id,
usercount
sum(usercount) over(order by usercount rows unbounded preceding)
as sequenceusercount
from Table

T-sql rank for max and min value

I need help with a t-sql query.
I have a table with this structure:
id | OverallRank | FirstRank | SecondRank | Nrank..
1 | 10 | 20 | 30 | 5
2 | 15 | 24 | 12 | 80
3 | 10 | 40 | 37 | 12
I need a query that produces this kind of result:
When id: 1
id | OverallRank | BestRankLabel | BestRankValue | WorstRankLabel | WorkRankValue
1 | 10 | SecondRank | 30 | Nrank | 5
When id: 2
id | OverallRank | BestRankLabel | BestRankValue | WorstRankLabel | WorkRankValue
1 | 15 | FirstRank | 24 | SecondRank | 12
How can I do it?
Thanks in advance
with cte(id, RankValue,RankName) as (
SELECT id, RankValue,RankName
FROM
(SELECT id, OverallRank, FirstRank, SecondRank, Nrank
FROM ##input) p
UNPIVOT
(RankValue FOR RankName IN
(OverallRank, FirstRank, SecondRank, Nrank)
)AS unpvt)
select t1.id, max(case when RankName = 'OverallRank' then RankValue else null end) as OverallRank,
max(case when t1.RankValue = t2.MaxRankValue then RankName else null end) as BestRankName,
MAX(t2.MaxRankValue) as BestRankValue,
max(case when t1.RankValue = t3.MinRankValue then RankName else null end) as WorstRankName,
MAX(t3.MinRankValue) as WorstRankValue
from cte as t1
left join (select id, MAX(RankValue) as MaxRankValue from cte group by id) as t2 on t1.id = t2.id
left join (select id, min(RankValue) as MinRankValue from cte group by id) as t3 on t1.id = t3.id
group by t1.id
Working good with your test data. You should only edit RankName IN (OverallRank, FirstRank, SecondRank, Nrank) by adding right columns' names.
CASE
WHEN OverallRank > FirstRank and OverallRank > FirstSecondRand and OverallRank > nRank THEN 'OverallRank'
WHEN FirstRank > OverallRank ... THEN 'FirstRank'
END
This kind of query is why you should normalise your data.
declare #id int, #numranks int
select #id = 1, #numranks = 3 -- number of Rank columns
;with cte as
(
select *
from
(
select *,
ROW_NUMBER() over (partition by id order by rank desc) rn
from
(
select * from YourBadlyDesignedTable
unpivot (Rank for RankNo in (FirstRank, SecondRank, ThirdRank))u -- etc
) v2
) v1
where id=#id and rn in (1, #numranks)
)
select
tMin.id,
tMin.OverallRank,
tMin.RankNo as BestRankLabel,
tMin.Rank as BestRankValue,
tMax.RankNo as WorstRankLabel,
tMax.Rank as WorstRankValue
from (select * from cte where rn=1) tMin
inner join (select * from cte where rn>1) tMax
on tMin.id = tmax.id
You can take out the id = #id if you want all rows.

Select and merge rows in a table in SQL Stored procedure

Have a temp table with schema: ID | SeqNo | Name
ID - Not unique
SeqNo - Int (can be 1,2 or 3). Sort of ID+SeqNo as Primary key
Name - Any text
And sample data in the table like this
1 | 1 | RecordA
2 | 1 | RecordB
3 | 1 | RecordC
1 | 2 | RecordD
4 | 1 | RecordE
5 | 1 | RecordF
3 | 1 | RecordG
Need to select from this table and output like
1 | RecordA/RecordD
2 | RecordB
3 | RecordC/RecordG
4 | RecordE
5 | RecordF
Need to do this without cursor.
If SeqNo is limited to 1,2,3:
select id, a.name + coalesce('/'+b.name, '') + coalesce('/'+c.name, '')
from myTable a
left outer join myTable b on a.id=b.id and b.seqno = 2
left outer join myTable c on a.id=c.id and c.seqno = 3
where a.seqno = 1;
If SeqNo is open ended you can deploy a recursive cte:
;with anchor as (
select id, name, seqno
from myTable
where seqno=1)
, recursive as (
select id, name, seqno
from anchor
union all
select t.id, r.name + '/' + t.name, t.seqno
from myTable t
join recursive r on t.id = r.id and r.seqno+1 = t.seqno)
select id, name from recursive;
If you know SeqNo will never be more than 3:
select Id, Names = stuff(
max(case when SeqNo = 1 then '/'+Name else '' end)
+ max(case when SeqNo = 2 then '/'+Name else '' end)
+ max(case when SeqNo = 3 then '/'+Name else '' end)
, 1, 1, '')
from table1
group by Id
Otherwise, something like this is the generic solution to an arbitrary number of items:
select Id, Names = stuff((
select '/'+Name from table1 b
where a.Id = b.Id order by SeqNo
for xml path (''))
, 1, 1, '')
from table1 a
group by Id
Or write a CLR UDA.
Edit: had the wrong alias on the correlated table!
Edit2: another version, based on Remus's recursion example. I couldn't think of any way to select only the last recursion per Id, without aggregation or sorting. Anybody know?
;with
myTable as (
select * from (
values
(1, 1, 'RecordA')
, (2, 1, 'RecordB')
, (3, 1, 'RecordC')
, (1, 2, 'RecordD')
, (4, 1, 'RecordE')
, (5, 1, 'RecordF')
, (3, 2, 'RecordG')
) a (Id, SeqNo, Name)
)
, anchor as (
select id, name = convert(varchar(max),name), seqno
from myTable where seqno=1
)
, recursive as (
select id, name, seqno
from anchor
union all
select t.id, r.name + '/' + t.name, t.seqno
from myTable t
join recursive r on t.id = r.id and r.seqno+1 = t.seqno
)
select id, name = max(name)
from recursive
group by id;
---- without aggregation, we get 7 rows:
--select id, name
--from recursive;
The solution is good. I have a similar issue, but here I am using 2 different tables. ex:
table1
1 | 1 |
2 | 3 |
3 | 1 |
4 | 2 |
5 | 1 |
1 | 2 |
1 | 3 |
4 | 1 |
5 | 2 |
2 | 2 |
4 | 3 |
table2
1 | RecordA
2 | RecordB
3 | RecordC
I want to get the data from two tables and display in the below format.
1 | RecordA,RecordB,RecordC|
2 | RecordB,RecordC|
3 | RecordA |
4 | RecordA,RecordB,RecordC|
5 | RecordA,RecordB |