T-SQL query in SQL Server - sql-server

I want to write a query where this should meet the condition shown in the first screenshot. Currently, I am getting second screenshot data which is not correct. I am having a hard time achieving this.
SELECT
CONCAT(p.[prefNameFamilyName], ' ', p.[prefNameGivenName], ' ', p.[prefNameMiddleNames], ' ', pre.code, ' ', nt.code) AS PatientName,
CONCAT(pn.familyName, ' ', pn.givenName, ' ', pn.middleNames, ' ', nt.code) AS PatientAlias,
CONCAT(pa.streetAddressLine1, ' ', pc.code, ' ', sp.code, ' ', ap.code, ' ', ac.code, ' ', atp.code) AS PatientAddress
FROM
identifier.identifier I
INNER JOIN
[Patient].[Patient] p ON i.id = p.patientIdentifierId
INNER JOIN
[Patient].PatientName pn ON pn.patientId = p.id
INNER JOIN
[Identifier].[LK_NamePrefix] pre ON pre.id = p.prefNamePrefixId
INNER JOIN
[Identifier].[LK_NameType] nt ON nt.id = pn.nameTypeId
LEFT JOIN
Patient.PatientAddress a ON a.patientId = p.id
INNER JOIN
[Patient].[PatientAddress] pa ON pa.patientId = p.id
INNER JOIN
[Address].[City] pc ON pa.cityId = pc.id
LEFT JOIN
[Address].[Country] ac ON ac.id = pa.countryId
LEFT JOIN
[Address].[StateOrProvince] sp ON sp.id = pa.stateOrProvinceId
LEFT JOIN
[Address].[Postcode] ap ON ap.id = pa.postcodeId
LEFT JOIN
[Address].[AddressType] atp ON atp.id = pa.addressTypeId
WHERE
I.identifier = 'ABC123'

You could use common table expressions (CTE's) to isolate the joins. This solution generates row numbers for the different combinations and joins on the row numbers later on. The final step is to filter out the rows with only null values. This solution works for any combination of a name, one or more aliases and one or more addresses.
Sample data
declare #names table
(
id int,
name nvarchar(20)
);
insert into #names (id, name) values
(1, 'Bruce Wayne'),
(2, 'Peter Parker'),
(3, 'Clark Kent');
declare #aliases table
(
id int,
alias nvarchar(20)
)
insert into #aliases (id, alias) values
(1, 'Batman'),
(1, 'The bat'),
(1, 'Batty'),
(2, 'Spider-Man'),
(2, 'Spidey'),
(3, 'Superman');
declare #addresses table
(
id int,
address nvarchar(20)
);
insert into #addresses (id, address) values
(1, 'Wayne Manor'),
(1, 'The Cave'),
(2, 'Aunt May''s house'),
(3, 'The Daily Planet'),
(3, 'Krypton');
Solution
with cte_na as
(
select na.id,
na.name,
row_number() over(partition by na.id order by na.name) as nameNum
from #names na
left join #aliases al
on al.id = na.id
left join #addresses ad
on ad.id = na.id
),
cte_al as
(
select al.id,
al.alias,
row_number() over(partition by al.id order by al.alias) as aliasNum
from #aliases al
),
cte_ad as
(
select ad.id,
ad.address,
row_number() over(partition by ad.id order by ad.address) as addressNum
from #addresses ad
)
select cna.id,
cna.name,
coalesce(cal.alias, '') as alias,
coalesce(cad.address, '') as address
from cte_na cna
left join cte_al cal
on cal.id = cna.id
and cal.aliasNum = cna.nameNum
left join cte_ad cad
on cad.id = cna.id
and cad.addressNum = cna.nameNum
where not (cal.id is null and cad.id is null);
Result
id name alias address
----------- -------------------- -------------------- --------------------
1 Bruce Wayne Batman The Cave
1 Bruce Wayne Batty Wayne Manor
1 Bruce Wayne The bat
2 Peter Parker Spider-Man Aunt May's house
2 Peter Parker Spidey
3 Clark Kent Superman Krypton
3 Clark Kent The Daily Planet

Related

How to present row data in Comma seperated list when multiple table joins involved in SQL Server 2014

I want to present multiple rows data for a particular Id in comma separated list. If it has only one join I have no problem to display but when it includes many tables it is not presented properly.
My data is as follows.
Declare #EmpClass Table(ClassId varchar(10),EmpId int)
INSERT INTO #EmpClass
Values('A',1)
,('B',2)
,('C',3)
Declare #Employees Table (EmpId int, EmpName Varchar(100))
INSERT INTO #Employees
VALUES(1,'RAM')
,(2,'RAJ')
,(3,'LAXMAN')
Declare #EmpSubjects Table (EmpId int, SubjectId int)
INSERT INTO #EmpSubjects
VALUES(1,1)
,(1,2)
,(1,3)
,(2,1)
,(3,1)
,(3,2)
Declare #Subjects Table (SubjectId int, Subject Varchar(100))
INSERT INTO #Subjects
VALUES(1,'Maths')
,(2,'Science')
,(3,'Physics')
,(4,'Physics')
,(5,'Maths')
,(6,'Physics')
I have tried the below code and got the below result
SELECT EC.ClassId,E.EmpId
,ES.SubjectId,Subject
FROM #EmpClass EC
LEFT JOIN #Employees E ON EC.EmpId=E.EmpId
LEFT JOIN #EmpSubjects ES ON E.EmpId=ES.EmpId
LEFT JOIN #Subjects S ON S.SubjectId=ES.SubjectId
WHERE E.EmpId=1
I got the below result
ClassId EmpId SubjectId Subject
A 1 1 Maths
A 1 2 Science
A 1 3 Physics
The result needed as follows.
ClassId EmpId SubjectId Subject
A 1 1 {"1":"Maths","2":"Science","3":"Physics"}
I appreciate your help for this.
Thanks
The comma-separated data in your expected result looks like JSON to me. Have you tried something like this?
SELECT EC.ClassId,E.EmpId,
Subject = (
SELECT [1], [2], [3], [4], [5], [6]
FROM (
SELECT S.SubjectID, S.Subject
FROM #EmpSubjects ES
LEFT JOIN #Subjects S ON S.SubjectId=ES.SubjectId
WHERE ES.EmpId=E.EmpId
) as Src
PIVOT (
MAX([Subject])
for [SubjectID] in ([1], [2], [3], [4], [5], [6])
) as p
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
FROM #EmpClass EC
LEFT JOIN #Employees E ON EC.EmpId=E.EmpId
WHERE E.EmpId=1
Which yields the result:
ClassId EmpId Subject
-------- ------ -----------------------------------------
A 1 {"1":"Maths","2":"Science","3":"Physics"}
With 2014 it's a little bit more of a challange but here's an option using the xml functions:
SELECT [Results].[ClassId]
, [Results].[EmpId]
, '{' + STUFF((SELECT ',"' + CONVERT(VARCHAR(2), tb.[SubjectId]) + '":"' + CAST(tb.[Subject] AS VARCHAR(MAX)) + '"'
FROM (
SELECT [EC].[ClassId]
, [E].[EmpId]
, [ES].[SubjectId]
, [S].[Subject]
FROM #EmpClass [EC]
LEFT JOIN #Employees [E]
ON [EC].[EmpId] = [E].[EmpId]
LEFT JOIN #EmpSubjects [ES]
ON [E].[EmpId] = [ES].[EmpId]
LEFT JOIN #Subjects [S]
ON [S].[SubjectId] = [ES].[SubjectId]
) AS [tb]
WHERE ( [tb].[ClassId] = [Results].[ClassId] AND tb.[EmpId] = [Results].[EmpId] )
FOR XML PATH(''), TYPE
).[value]('(./text())[1]', 'VARCHAR(MAX)'), 1, 1, '') + '}' AS [Subjects]
FROM (
SELECT [EC].[ClassId]
, [E].[EmpId]
, [ES].[SubjectId]
FROM #EmpClass [EC]
LEFT JOIN #Employees [E]
ON [EC].[EmpId] = [E].[EmpId]
LEFT JOIN #EmpSubjects [ES]
ON [E].[EmpId] = [ES].[EmpId]
) [Results]
WHERE [Results].[EmpId] = 1
GROUP BY [Results].[ClassId], [Results].[EmpId]
Giving you the results of:
ClassId EmpId Subjects
---------- ----------- -------------------------------------------
A 1 {"1":"Maths", "2":"Science", "3":"Physics"}
The first sub-query is converting to XML using the FOR XML, so we can basically aggregate the columns. Then STUFF() to remove the leading "," from it. Then wrap that with "{}"

Select all users from subgroups in T-SQL query [duplicate]

This question already has an answer here:
SQL Server recursive self join
(1 answer)
Closed 3 years ago.
I have a SQL Server table that holds groups and subgroups that I am using to define user permissions in application. What I am trying to accomplish is to select all users ids from all subgroups based on used id assigned to group.
I have tried with this query but it only shows one level of subgroup users.
SET #UserIds =
ISNULL(
STUFF((SELECT ',' + CAST(tbl.UserID AS VARCHAR(MAX))
FROM
(SELECT grpUser.UserId AS UserID
FROM dbo.GroupUser grpUser
INNER JOIN (SELECT subGrp.Id, subGrp.GroupName
FROM dbo.Groups grp
INNER JOIN dbo.GroupUser guser ON grp.Id = guser.GroupId
AND guser.UserId = #UserId
INNER JOIN dbo.Groups subGrp ON grp.Id = subGrp.ParentGroupId) tbl ON grpUser.GroupId = tbl.Id) AS tbl
FOR XML PATH('')), 1, 1, ''), '')
I am struggling to get users ids in all subgroups. Number of subgroups is not defined. Is there a way to do in sql or should I shift this part to application side? Thank you for any advice.
Finally I came up with this code. Thank you for hint.
declare #UserGroupId int;
Set #UserGroupId = (Select GroupId from GroupUser gu
left join dbo.Groups gr on gu.GroupId = gr.id
where UserId = #UserId and gr.IsDeleted = 0)
declare #UsersGroups Table (
Id int not null,
GroupName nvarchar(50) not null
)
;WITH grp AS
(
SELECT Id, GroupName
FROM Groups
WHERE ParentGroupId = 1
UNION ALL
SELECT g.Id, g.GroupName
FROM Groups g
INNER JOIN dbo.GroupUser guser ON g.Id = guser.GroupId
INNER JOIN grp ON g.ParentGroupId = grp.Id
)
Insert into #UsersGroups
SELECT Id, GroupName
FROM grp
SET #UserIds = ISNULL(STUFF(( SELECT ',' + CAST(tbl.UserID AS VARCHAR(max)) FROM (
SELECT grpUser.UserId AS UserID FROM dbo.GroupUser grpUser
INNER JOIN ( SELECT * FROM #UsersGroups
) tbl ON grpUser.GroupId = tbl.Id
) AS tbl FOR XML PATH('') ), 1, 1, ''), '')

SQL - Comma Delimited subset results of multiple column in its own column

I have a view with a union all table, a person may belong to one or many table.
how do i create a query that will add a column with a ';' delimited where the person belong to, the ID is unique per person.
here's the example
--table1
PID fName tableMem
1 test group1
2 test2 group1
--table2
PID fName tableMem
1 test group2
3 test3 group2
--table3
PID fName tableMem
1 test group3
3 test3 group3
Here's the output I wanted
--compiled table after union of all the 3 tables
PID fname tableMem
1 test group1;group2;group3
2 test2 group1
3 test3 group2;group3
Here's the query I built from reading here for the past 2 days.I'm using STUFF and partition because I need the row to be distinct and this query will run as view.
SELECT *
FROM
(SELECT
*,
ROW_NUMBER() OVER(PARTITION BY PIP ORDER BY Fname) AS rownum
FROM
(SELECT
*,
STUFF((SELECT ';'+ di.tablemem
FROM DPI di <<-- alias table from union
WHERE DPI.PID = di.PID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') tablemem
FROM
(SELECT *
FROM
(--table1
SELECT 'group1' AS tableMem, * FROM table1
UNION ALL
--table2
SELECT 'group2' AS tableMem, * FROM table2
UNION ALL
--table3
SELECT 'group3' AS tableMem, * FROM table3) AS DPI <<--alias table name
) AS innertable
) AS distinctTable
) AS outerTable
WHERE
rownum = 1
what am I missing or what is wrong with the query. I'm guessing its because Im using a derived table name of the union sub select. is there any workaround?
Thank you in advance
You need GROUP BY data by PID, fName, using the FOR XML aggregation it would be
WITH DPI AS (
--table1
Select 'group1' as tableMem,* from table1
UNION ALL
--table2
Select 'group2' as tableMem,* from table2
UNION ALL
--table3
Select 'group3' as tableMem,* from table3
)
SELECT PID, fName
, STUFF((
SELECT ';'+ di.tablemem
FROM DPI di
WHERE di.PID = di1.PID
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'') tablemem
FROM DPI di1
GROUP BY PID, fName;
Here is a possible solution using CTE:
;with cte as (
select * from #tbl1
union all
select * from #tbl2
union all
select * from #tbl3
)
select distinct
pid
,fname
,stuff(
(select '; ' + tableMem
from cte
where pid = a.pid
and fname = a.fname
FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'') as tableMem
from cte a
Given that you have a finite number of tables, I think I find this simpler:
select p.pid, p.fname,
trim(';' from
(case when t1.pid is not null then 'group1;' else '' end) +
(case when t2.pid is not null then 'group2;' else '' end) +
(case when t3.pid is not null then 'group3;' else '' end)
) as groups
from (select pid, fname from table1 union -- on purpose to remove duplicates
select pid, fname from table2 union
select pid, fname from table3
) p left join
table1 t1
on t1.pid = p.pid left join
table2 t2
on t2.pid = p.pid left join
table3 t3
on t3.pid = p.pid;
The most recent version of SQL Server supports string_agg(), which would make this simpler still.
Try this:
DECLARE #table1 TABLE
(
[PID] TINYINT
,[fname] VARCHAR(12)
,[tableMem] VARCHAR(12)
);
DECLARE #table2 TABLE
(
[PID] TINYINT
,[fname] VARCHAR(12)
,[tableMem] VARCHAR(12)
);
DECLARE #table3 TABLE
(
[PID] TINYINT
,[fname] VARCHAR(12)
,[tableMem] VARCHAR(12)
);
INSERT INTO #table1 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group1')
,(2, 'test2', 'group1');
INSERT INTO #table2 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group2')
,(3, 'test3 ', 'group2');
INSERT INTO #table3 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group3')
,(3, 'test3 ', 'group3');
WITH DataSource AS
(
SELECT *
FROM #table1
UNION ALL
SELECT *
FROM #table2
UNION ALL
SELECT *
FROM #table3
)
SELECT DISTINCT DS.[PID]
,DS.fname
,CSVvalue.[tableMem]
FROM DataSource DS
CROSS APPLY
(
SELECT STUFF
(
(
SELECT ',' + DS1.[tableMem]
FROM DataSource DS1
WHERE DS.[PID] = DS1.[PID]
AND DS.[fname] = DS1.[fname]
ORDER BY DS1.[tableMem]
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1
,1
,''
)
) CSVvalue ([tableMem]);

SQL Server: How to show list of manager name separated by comma

i have to show employee name and his manager name hierarchy separated by comma.
if ram is top manager and ram is sam manager and sam is rahim manager then i would like to have output like
Desired output
EMP Name Manager's Name
--------- ---------------
Rahim Sam,Ram
Sam Ram
Ram No manager
i got script which show the employee and his manager name. here is script
;WITH EmployeeCTE AS
(
Select ID,Name,MgrID, 0 as level FROM #Employee
WHERE ID=3
UNION ALL
Select r.ID,r.Name,r.MgrID, level+1 as level
FROM #Employee r
JOIN EmployeeCTE p on r.ID = p.MgrID
)
Select e1.Name
,ISNULL(e2.Name,'Top BOSS') as [Manager Name]
,row_number() over (order by e1.level desc) as [Level]
from EmployeeCTE e1
left join EmployeeCTE e2 on e1.MgrID=e2.ID
Output
Name Manager Name Level
Simon Top BOSS 1
Katie Simon 2
John Katie 3
i also know how to show comma separated list. here is one sample script.
SELECT
PNAME,
STUFF
(
(
SELECT ',' + Mname
FROM Myproducts M
WHERE M.PNAME = P.PNAME
ORDER BY Mname
FOR XML PATH('')
), 1, 1, ''
) AS Models
FROM
Myproducts p
GROUP BY PNAME
now some tell me how could i merge two script to get the desired output. thanks
CREATE TABLE #EMP (
EmpID INT
, ManagerID INT
, Name NVARCHAR(50) NULL
);
INSERT INTO #EMP (EmpID, ManagerID, Name)
VALUES
( 1, NULL, 'John')
, (2, 1, 'Katie')
, (3, 2, 'Simon');
SELECT *
FROM
#EMP;
WITH a AS (
SELECT
EmpID
, Name
, ManagerID
, CONVERT(NVARCHAR(MAX),'') AS ManagerChain
FROM
#Emp
WHERE
ManagerID IS NULL
UNION ALL
SELECT
e.EmpID
, e.Name
, e.ManagerID
, CASE
WHEN a.ManagerChain ='' THEN a.Name
ELSE CONCAT(a.Name, CONCAT(',',a.ManagerChain))
END
FROM
#Emp e
JOIN a ON e.ManagerID = a.EmpID
)
SELECT
a.Name
, IIF(a.ManagerChain='','No Manager',a.ManagerChain) AS ManagerChain
FROM
a;
DROP TABLE #EMP;
Assuming a table structure of
DECLARE #Employee TABLE(
ID INT,
Name VARCHAR(10),
MgrID INT)
INSERT INTO #Employee
VALUES (1,'Ram',NULL),
(2,'Sam',1),
(3,'Rahim',2);
You can use
WITH EmployeeCTE
AS (SELECT ID,
Name,
MgrID,
0 AS level,
CAST('No manager' AS VARCHAR(8000)) AS [Managers Name]
FROM #Employee
WHERE MgrID IS NULL
UNION ALL
SELECT r.ID,
r.Name,
r.MgrID,
level + 1 AS level,
CAST(P.Name + CASE
WHEN level > 0
THEN ',' + [Managers Name]
ELSE ''
END AS VARCHAR(8000))
FROM #Employee r
JOIN EmployeeCTE p
ON r.MgrID = p.ID)
SELECT *
FROM EmployeeCTE

Merging results from SQL Query, where most values are the same [duplicate]

This question already has answers here:
Simulating group_concat MySQL function in Microsoft SQL Server 2005?
(12 answers)
Closed 6 years ago.
Sorry for the not-so-great title.
I'm triyng to merge together sets of results to provide a quick view of some data.
If I have this query:
SELECT
tblPriv.ID, tblGroups.Name AS 'Group', tblPriv.User, tblPriv.Role
FROM
tblPriv
INNER JOIN
tblGroups on tblPriv.ID = tblGroups.ID
which returns these results:
ID GROUP USER ROLE
---------------------------------
1 Taxes DAVE Admin
1 Taxes JOHN Admin
1 Taxes BOB PowerUser
2 Catering RON Admin
2 Catering JACK PowerUser
2 Catering JIM PowerUser
(where ID is relational to say, a group, stored in another table)
What I ideally want to do is get 1 record for a group:
ID GROUP ADMINS POWERUSERS
---------------------------------------------
1 Taxes DAVE; JOHN; BOB
2 Catering RON; JACK; JIM;
I know the roles beforehand - they always stay the same, and new roles are not added, ever.
How would I go about doing this? (I will also include data from other relational tables)
SELECT
DISTINCT tp.ID,
tp.[GROUP],
ISNULL(STUFF(Admins.Admins, 1, 1, ''), '') AS Admins,
ISNULL(STUFF(PowerUsers.PowerUsers, 1, 1, ''), '') AS PowerUsers
FROM tlbPriv AS tp
OUTER APPLY
(
SELECT ' ' + tmp.[USER] + ';'
FROM tlbPriv AS tmp
WHERE tmp.ID = tp.ID AND [tmp].[ROLE] = 'Admin' FOR XML PATH('')
)Admins(Admins)
OUTER APPLY
(
SELECT ' ' + tmp.[USER] + ';'
FROM tlbPriv AS tmp
WHERE tmp.ID = tp.ID AND [tmp].[ROLE] = 'PowerUser' FOR XML PATH('')
)PowerUsers(PowerUsers)
For your particular problem:
select g.id, g.name,
stuff((select '; ' + p.user
from tblPriv p
where p.id = g.id and p.role = 'Admin'
for xml path ('') type
).value('', 'varchar(max)'
), 1, 2, ''
) as admins,
stuff((select '; ' + p.user
from tblPriv p
where p.id = g.id and p.role = 'PowerUser'
for xml path ('') type
).value('', 'varchar(max)'
), 1, 2, ''
) as PowerUsers
from tblGroups g
Tagged tsql, I assume this is for MS SQL server:
DECLARE #users TABLE
(
[ID] INT ,
[GROUP] VARCHAR(8) ,
[USER] VARCHAR(4) ,
[ROLE] VARCHAR(9)
);
INSERT INTO #users
( [ID], [GROUP], [USER], [ROLE] )
VALUES ( 1, 'Taxes', 'DAVE', 'Admin' ),
( 1, 'Taxes', 'JOHN', 'Admin' ),
( 1, 'Taxes', 'BOB', 'PowerUser' ),
( 2, 'Catering', 'RON', 'Admin' ),
( 2, 'Catering', 'JACK', 'PowerUser' ),
( 2, 'Catering', 'JIM', 'PowerUser' );
WITH data ( ID, [GROUP], [ROLE], [MEMBERS] )
AS ( SELECT u.ID ,
u.[GROUP] ,
u.ROLE ,
( SELECT [USER] + ';'
FROM #users AS [u1]
WHERE u.ID = u1.ID AND u.[GROUP] = u1.[GROUP] and u.ROLE = u1.ROLE
FOR
XML PATH('')
)
FROM #users AS [u]
)
SELECT ID ,
[GROUP] ,
[Admin] AS [Admins] ,
[PowerUser] AS [POWERUSERS]
FROM data PIVOT ( MAX(MEMBERS) FOR [ROLE] IN ( [Admin], [PowerUser] ) ) pvt;
In MYSQL Use group concat
SELECT
tblPriv.ID
, tblGroups.Name AS 'Group'
, group_concat(t1.User) AS ADMINS, group_concat(t2.User) AS POWERUSERS
FROM tblPriv
INNER JOIN tblGroups as t1 on t1.ID = tblGroups.ID and t1.user='ADMIN'
INNER JOIN tblGroups as t2 on t2.ID = tblGroups.ID and t1.user='POWERUSER'
GROUP BY tblPriv.ID

Resources