SQL select Top x records for two columns - sql-server

I have a table like this
ProjectID PhaseID Comment CommentDate
1 1 a 2/15/2014
1 1 b 5/1/2014
1 2 c 8/15/2014
1 2 d 1/1/2015
2 1 e 1/21/2014
2 2 f 5/15/2014
2 2 g 1/1/2015
How do I get the lastest (Top 1) comment for each project for each phase? For example, for Project 1, phase 1, I should get "b" and "5/1/2014"
Thank you!

select ProjectID,PhaseID,Comment,CommentDate from
(select row_number() over(partition by Project_ID,PhaseID order by CommentDate desc) as rn,* from table) a
where a.rn = 1

This type of query works best when there's an identity column (and values are always inserted in order) but this should get you what you need assuming there's no overlapping commentDates
select t.*
from table t
inner join (
SELECT max(commentDate) as maxDate,
phaseId,
projectId
FROM table
group by phaseId, projectId
) maxComments on t.phaseId = maxComments.phaseId
and t.projectId = maxComments.projectId
and t.commentDate = maxComments.maxDate

Related

SQL Server - select column using in having count()

This is my first question (and sorry for my English)
I have this table in SQL Server:
id_patient | date | id_drug
----------------------------------------------------
1 20200101 A
1 20200102 A
1 20200103 A
1 20200104 A
1 20200105 A
1 20200110 A
2 20200101 A
2 20200105 B
2 20200106 C
2 20200107 D
2 20200108 E
2 20200110 L
3 20200101 A
3 20200102 A
3 20200103 A
3 20200104 A
3 20200105 C
3 20200106 C
4 20200105 A
4 20200106 D
4 20200107 D
5 20200105 A
5 20200106 A
5 20200107 C
5 20200108 D
I would like to extract patient and drug for all patients who have taken at least 3 different drugs in a given period
I have tried:
select id_patient, count(distinct ID_drug)
from table
where date between XXX and YYY
group by id_patient
having count(Distinct ID_drug) > 3
but in this way -YES- I get all patients with 3 or more different id_drug in this date range but I can't get the ID_drug because in the count()
For example, I'd like to obtain:
Who help me ?
Thanks
You can use string_agg() in the most recent versions of SQL Server:
select id_patient, count(distinct ID_drug),
string_agg(id_drug, ',')
from table
where date between XXX and YYY
group by id_patient
having count(Distinct ID_drug) > 3;
If you want the original rows, you can use window functions. Unfortunately, SQL Server does not support count(distinct) as a window function, but there is an easy work-around using dense_rank():
select t.*
from (select t.*,
(dense_rank() over (partition by id_patient order by id_drug) +
dense_rank() over (partition by id_patient order by id_drug desc)
) as num_drugs
from t
where . . .
) t
where num_drugs >= 3;
SELECT id_patient,
ID_drug
FROM table
WHERE id_patient IN (
SELECT id_patient
FROM table
WHERE date
BETWEEN XXX
AND YYY
GROUP BY id_patient
HAVING COUNT(DISTINCT ID_drug) >= 3
)
GROUP BY id_patient,
ID_drug;

How do you dynamically Assing Unique Code for every row iin hierarchical table?

My table.
Table1
Id ParentId Name Code
1 Null John
2 1 Harry
3 1 Mary
4 2 Emma
5 2 Kyle
6 4 Robert
7 Null Rohit
I want to assign each individual with the the following format unique hierarchy codes
Output Required
Id ParentId Name Code
1 Null John 1
2 1 Harry 1.1
3 1 Mary 1.2
4 2 Emma 1.1.1
5 2 Kyle 1.1.2
6 4 Robert 1.1.1.1
7 Null Rohit 2
and so on.
I hope I've got this correctly...
You can use a recursive CTE together with ROW_NUMBER() in order to create your codes.
DECLARE #dummy TABLE(Id INT,ParentId INT,[Name] VARCHAR(100));
INSERT INTO #dummy(Id,ParentId,[Name]) VALUES
(1,Null,'John')
,(2,1 ,'Harry')
,(3,1 ,'Mary')
,(4,2 ,'Emma')
,(5,2 ,'Kyle')
,(6,4 ,'Robert')
,(7,Null,'Rohit');
WITH recCTE AS
(
SELECT Id,ParentId,[Name]
,CONCAT(N'.',CAST(ROW_NUMBER() OVER(ORDER BY Id) AS NVARCHAR(MAX))) AS Code
FROM #dummy WHERE ParentId IS NULL
UNION ALL
SELECT d.Id,d.ParentId,d.[Name]
,CONCAT(r.Code,N'.', ROW_NUMBER() OVER(ORDER BY d.Id))
FROM #dummy d
INNER JOIN recCTE r ON d.ParentId=r.Id
)
SELECT Id,ParentId,[Name]
,STUFF(Code,1,1,'') AS Code
FROM RecCTE;
The idea in short:
We pick the rows with ParentId IS NULL and give them a running number.
Now we go iteratively through them (it's a hidden RBAR actually) and call their children, again with a running number.
This we do until there is nothing left.
the final SELECT needs a STUFF in order to to get rid of the first dot.
And with an extension like this, you can create an alphanumerically sortable code:
WITH recCTE AS
(
SELECT Id,ParentId,[Name]
,CONCAT(N'.',CAST(ROW_NUMBER() OVER(ORDER BY Id) AS NVARCHAR(MAX))) AS Code
,CONCAT(N'000',CAST(ROW_NUMBER() OVER(ORDER BY Id) AS NVARCHAR(MAX))) AS Code2
FROM #dummy WHERE ParentId IS NULL
UNION ALL
SELECT d.Id,d.ParentId,d.[Name]
,CONCAT(r.Code,N'.', ROW_NUMBER() OVER(ORDER BY d.Id))
,CONCAT(r.Code2,RIGHT(CONCAT('0000',ROW_NUMBER() OVER(ORDER BY d.Id)),4))
FROM #dummy d
INNER JOIN recCTE r ON d.ParentId=r.Id
)
SELECT Id,ParentId,[Name]
,STUFF(Code,1,1,'') AS Code
,Code2
FROM RecCTE
ORDER BY Code2;

How to select the value from the table based on category_id USING SQL SERVER

How to select the value from the table based on category_id?
I have a table like this. Please help me.
Table A
ID Name category_id
-------------------
1 A 1
2 A 1
3 B 1
4 C 2
5 C 2
6 D 2
7 E 3
8 E 3
9 F 3
How to get the below mentioned output from table A?
ID Name category_id
--------------------
1 A 1
2 A 1
4 C 2
5 C 2
7 E 3
8 E 3
Give a row number for each row based on group by category_id and sort by ascending order of ID. Then select the rows having row number 1 and 2.
Query
;with cte as (
select [rn] = row_number() over(
partition by [category_id]
order by [ID]
), *
from [your_table_name]
)
select [ID], [Name], [category_id]
from cte
where [rn] < 3;
Kindly run this query It really help You Out.
SELECT tbl.id,tbl.name, tbl.category_id FROM TableA as tbl WHERE
tbl.name IN(SELECT tbl2.name FROM TableA tbl2 GROUP BY tbl2.name HAVING Count(tbl2.name)> 1)
Code select all category_id from TableA which has Name entries more then one. If there is single entry of any name group by category_id then such data will be excluded. In above example questioner want to eliminate those records that have single Name entity like wise category_id 1 has name entries A and B among which A has two entries and B has single entry so he want to eliminate B from result set.

Get Sum of Count

The View obtains the first three columns. I need to add one more column (totalCount) to the view that obtains the total count:
CId CCId CCount totalCount
1 a 3 6
1 a 3 6
1 b 3 6
1 c 3 6
2 b 2 6
2 b 2 6
2 a 2 6
2 a 2 6
3 v 1 6
How to get the totalCount as 6?
(Business rule for Cid=1 Ccount=3 Cid=2 Ccount=2 Cid=3 Ccount=1 So the totalCount =3+2+1 =6)
SELECT a.CID, a.CCID, a.CCOUNT,
b.TotalCount
FROM Table1 a, (SELECT SUM(DISTINCT cCOunt) TotalCount
FROM Table1) b
SQLFiddle Demo
UPDATE
As Andomar pointed out on the comment, An update has been made on the query,
SELECT a.CID, a.CCID, a.CCOUNT,
b.TotalCount
FROM Table1 a,
(
SELECT SUM(TotalCount) TotalCount
FROM
(
SELECT MAX(cCOunt) TotalCount
FROM Table1
GROUP BY CId
) c
) b
SQLFiddle Demo
With this code I came to the desired result:
select CId
,CCId
,CCount
,(select SUM(a.tcount)
from (select distinct CId ,CCount as tcount
from dbo.Test) as a ) totalcount
from dbo.Test
From your example data, I'm assuming a Cid can only have one, possibly repeated, value of CCount. In that case you can pick a random one (say max) using a group by, and sum those:
select sum(OneCCCount) as TotalCount
from (
select max(CCount) as OneCCCount
from YourTable
group by
CId
) as SubQueryAlias

SQL: Extract Row ID Based on the Min Value of Another Column

I can't seem to get this one. So I have a table like this:
RowID UserID Type Data
1 A A 1
2 A A 2
3 A B 1
4 A B 2
5 B A 1
6 B A 2
7 B B 1
8 B B 2
And I need to group this table by UserID and Type and then return the RowID for the record in each group that holds the MIN value in the Data column.
So for my result set would be:
1
3
5
7
For SQL Server >= 2005, you can do:
select RowID
from (
select RowID,
Rank() over (Partition BY UserID, Type
order by Data) as Rank
from MyTable
) tmp
where Rank = 1
SQL Fiddle Example
For SQL Server < 2005, you can do:
select t.RowID
from MyTable t
inner join (
select UserID, Type, min(Data) as MinData
from MyTable
group by UserID, Type
) tm on t.UserID = tm.UserID and t.Type = tm.Type
and t.Data = tm.MinData
SQL Fiddle Example

Resources