SQL Server Stuff() functions to concatenate data - sql

I am trying to retrieve data for a list of student conditions.
SELECT DISTINCT
DF.DFKEY AS StudentID
Condition = STUFF((SELECT DISTCINT ',' + DFCOND.ENR_COND
FROM DFCOND
WHERE DFCOND.SKEY = DF.DFKEY
GROUP BY DFCOND.ENR_COND
FOR XML PATH('')), 1, 1, '')
FROM
DF
LEFT JOIN
DFCOND ON df.dfkey = dfcond.skey
WHERE
DFCOND.ENR_COND IN ('12', 'CDOC', 'CONSUPP', 'CSEM')
ORDER BY
DF.DFKEY
So in this code. Each student can be assigned with many conditions but I only want to display ones that listed in WHERE IN conditions. DFCOND is the table to stored students condition data and DF is the table to store student information.
My problem is when I run it, all students conditions will be displayed so it skips the 'where in' function. How can I fix it?
For Example,
Student ID(DF.KEY) | DFCOND.ENR_COND (Conditions)
AA12 70%,12,DOC
since '12' is in the "where in" list, I only need
Student ID | condition1
AA12 12
These two tables are connected with DF.key and DFCOND.SKEY, they represent Student ID.
Thank you for any advice.

You want the filtering in the subquery:
select DF.DFKEY as StudentID,
STUFF((Select Distinct ',' + DFCOND.ENR_COND
from DFCOND
where DFCOND.SKEY = DF.DFKEY AND
DFCOND.ENR_COND in ('12', 'CDOC', 'CONSUPP', 'CSEM')
for xml path ('')
), 1, 1, ''
) as conditions
from DF
order by DF.DFKEY;
You also don't need the JOIN in the outer query. Nor the GROUP BY in the subquery.

Related

SQL query multiple rows into single row that has JOIN

I am trying to combine multiple rows into a single row that involves a JOIN. I cannot figure how to get the JOIN piece to work.
I am on SQL Server 2014.
This piece works great where I am rolling rows into a single comma separated line based on ID_REVIEW:
SELECT DISTINCT
ID_REVIEW
, STUFF((
SELECT N', ' + CAST(AREA_ID AS VARCHAR(255))
FROM AREA_ASSOC t2
WHERE t1.ID_REVIEW = t2.ID
FOR XML PATH('')
), 1, 1, '') AS AREA_ID
FROM REQUEST_WORKLOAD t1
Result:
ID_REVIEW | AREA_ID
-----------------
11438 | 2
23501 | 10, 15
44677 | 8
What I'd like to do is instead of having numbers for AREA_ID is have the name of that area show up. The goal being to have:
ID_REVIEW | AREA_NM
-----------------
11438 | State St.
23501 | Main St., Second St.
44677 | Adams Ave.
This AREA_NM information is contained in another table, called AREA. In a separate query, I can do a LEFT JOIN on table AREA_ASSOC to pull in the AREA_NM:
SELECT DISTINCT
[AREA_NM]
FROM AREA_ASSOC
LEFT JOIN AREA ON
AREA_ASSOC.AREA_ID = AREA.AREA_ID
I'm stumped as to how to get that JOIN into the STUFF function so I can get the area names. Is there a way to do this?
Do the join in the subquery:
SELECT DISTINCT r2.ID_REVIEW,
STUFF( (SELECT N', ' + a2AREA_NM
FROM AREA_ASSOC aa2 JOIN
AREA a
ON aa2.AREA_ID = A.AREA_ID
WHERE aa2.ID_REVIEW = r2.ID
FOR XML PATH('')
), 1, 2, ''
) AS AREA_ID
FROM REQUEST_WORKLOAD rw

How to get Comma separated Values IN SQL from 2 different tables using isnull stuff

Hi i have 2 different table "Users" and "UsersReportsTo"
there are two column as foreign key in UsersReportsTo Table column1 = Userid and column2 = ReportsTo, both contains userids
The result i want is comma separated email id of reportsto
please see the image
one user can report to multiple users like one teamleader to multiple assistance
i have tried below query but i am not getting proper result
select isnull(STUFF((SELECT ',' + Email
from UsersReportsTo urt
Left join Users rpt WITH (NOLOCK) on rpt.UserID=urt.UserID
WHERE active=1 and urt.UserID = 425 FOR XML PATH('')), 1, 1, ''),'') as rept
from UsersReportsTo
if i want Reportsto for UserId =3
Expected Result :-
qrst#g.com,abc#g.com,efg#g.com
try this in a query window and run it
WITH Email as (
SELECT rpt.Email as emailaddress
FROM Users rpt
WHERE active=1
AND urt.UserID = 3
UNION ALL
SELECT rpt2.Email as emailaddress
FROM UsersReportsTo urt --Teams
LEFT JOIN Users rpt WITH (NOLOCK) on urt.UserID = rpt.UserID
LEFT JOIN Users rpt2 WITH (NOLOCK) on rpt2.UserID=urt.ReportsTo
WHERE active=1
AND urt.UserID = 3
)
select isnull(STUFF((SELECT ',' + emailaddress from Email
FOR XML PATH('')), 1, 1, ''),'') as rept
You are seleting the user, then unioning the team leaders. From this cte you can delimit the list
You just need correct your where clause inside stuff() function:
select isnull(stuff((select',' + Email
from UsersReportsTo urt
left join Users rpt WITH (NOLOCK) on rpt.UserID = urt.ReportsTo
where u.userid = rpt.UserID and active = 1
for xml path('')), 1, 1, ''),'') as rept
from UsersReportsTo u
where UserId = 3
group by u.UserId;
Also read Bad habits : Putting NOLOCK everywhere
If, you have latest version of SQL Server (2017), then you can use STRING_AGG function
Thankyou for all your help.
I figured it out , selection of email id would be from users table my query was wrong now i found it, below is what i did.
select isnull(stuff((select',' + Email
from Users
left join UsersReportsTo WITH (NOLOCK) on UsersReportsTo.ReportsTo = Users.UserID
where Users.active = 1 and UsersReportsTo.userID = 425
for xml path('')), 1, 1, ''),'') as reptoemail

display more than one value using a SQL query

I am trying to display multiple authors per title in a single column. At the moment there a repeating rows, due to the fact that some Titles have more than 1 FirstName. Is there a form of concatenation that can be used to resolve this and display all the authors in a single filed and perhaps separated by a comma.
This is my current query:
SELECT
Submission.Title, Researcher.FirstName, Submission.Type
FROM
Submission
INNER JOIN
((Faculty
INNER JOIN
School ON Faculty.FacultyID = School.[FacultyID])
INNER JOIN
(Researcher
INNER JOIN
ResearcherSubmission ON Researcher.ResearcherID = ResearcherSubmission.ResearcherID)
ON School.SchoolID = Researcher.SchoolID)
ON Submission.SubmissionID = ResearcherSubmission.SubmissionID
GROUP BY
Submission.Title, Researcher.FirstName, Submission.Type;
This the output it generates:
[
this is the output I am trying to generate:
Title FirstName Type
---------------------------------------------------------------------------
21st Century Business Matthew, Teshar Book Chapter
A Family Tree... Keshant, Lawrence Book Chapter
Benefits of BPM... Jafta Journal Article
Business Innovation Matthew, Morna, Teshar Book Chapter
You may inclde the concantenation logic within a CROSS APPLY
SELECT
Submission.Title
, CA.FirstNames
, Submission.Type
FROM Submission
CROSS APPLY (
SELECT
STUFF((
SELECT /* DISTINCT ??? */
', ' + r.FirstName
FROM ResearcherSubmission rs
INNER JOIN Researcher r ON r.ResearcherID = rs.ResearcherID
WHERE Submission.SubmissionID = rs.SubmissionID
FOR XML PATH (''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, ' ')
) AS CA (FirstNames)
GROUP BY
Submission.Title
, CA.FirstNames
, Submission.Type
;
NB: I'm not sure if you need to include DISTINCT into the subquery when concatenating the names, e.g. if these was 'Jane' (Smith) and 'Jane' (Jones) do you want the final list as: 'Jane' or 'Jane, Jane'?
You can do this in your application logic as well.
But if you want to do this with a query. You should be able do something like this:
SELECT DISTINCT
sm.Title,
STUFF(
(SELECT ', ' + r.FirstName
FROM ResearcherSubmission rs
INNER JOIN Researcher r ON r.ResearcherID = rs.ResearcherID
WHERE sm.SubmissionID = rs.SubmissionID
FOR XML PATH('')), 1, 2, '') AS FirstNames,
sm.Type
FROM Submission sm
You can use the below query to generate the o/p as you want from the o/p that you have got.
CREATE TABLE #temptable(Title VARCHAR(200), FirstName VARCHAR(200), Type VARCHAR(200))
INSERT INTO #temptable
SELECT 'Book1','Matt','Chapter' UNION
SELECT 'Book1','Tesh','Chapter' UNION
SELECT 'BPM','Jafta','Article' UNION
SELECT 'Ethics','William','Journal' UNION
SELECT 'Ethics','Lawrence','Journal' UNION
SELECT 'Ethics','Vincent','Journal' UNION
SELECT 'Cellular','Jane','Conference'
SELECT Title
,STUFF((SELECT ', ' + CAST(FirstName AS VARCHAR(10)) [text()]
FROM #temptable
WHERE Title = t.Title
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
,Type
FROM #temptable t
GROUP BY Title,Type

SQL Aggregation of text on joined table

Pardon the lack of correct terminology, I'm a professional software engineer usually dealing with Direct3D frameworks. I'm self taught on databases.
I have a _People table and an _Ethnicities table. Since people may have more than one cultural group I have a link table _linkPersonEthnicity. Sample data is shown below:
What I want is output in the following form:
To illustrate the problem I present the following (runnable) query:
select lPE.Person, Sum(E.ID) as SumOfIDs,
Ethnicity = stuff(
(select ', ' + Max(E.Name) as [text()]
from _linkPersonEthnicity xPE
where xPE.Person = lPE.Person
for xml path('')
),
1, 2, '')
from _Ethnicities E
join _linkPersonEthnicity lPE on lPE.Ethnicity = E.ID
group by lPE.Person
It returns the Person's ID, a sum of the IDs found for the person's ethnicity, and concatenates the maximum Name with commas. The data is grouped correctly, and the SumOfIDs works, proving the correct data is used.
Naturally I would like to take away the Max aggregate function, but cannot since it is not in the group by list.
Any ideas how to make this work?
Thanks in advance,
AM
(Many thanks to other answers on StackOverflow for getting me this far! Particiularly #Jonathan Leffler for his explanation of the partitioning proceess and #Marc_s for illustrating a text concatenation technique.)
I've also tried coalesce from an answer to concatenating strings by #Chris Shaffer
declare #Names VARCHAR(8000)
select #Names = COALESCE(#Names + ', ', '') + E.Name
from _Ethnicities E join _linkPersonEthnicity lPE on lPE.Ethnicity = E.ID
where lPE.Person = 1001;
select #Names
Same problem. If I remove the where and add group by the text field Name cannot be accessed.
If I understand correctly, you need for the join to be in the subquery rather than the outer query
select lPE.Person, Sum(lpe.ethnicity) as SumOfIDs,
Ethnicity = stuff((select ', ' + E.Name as [text()]
from _linkPersonEthnicity lPE2 join
_Ethnicities e
on lpe2.Ethnicity = e.id
where lpe2.Person = lPE.Person
for xml path('')
), 1, 2, '')
from _linkPersonEthnicity lPE
group by lPE.Person;
By the way, do you really want the sum of the ids or a count?

JET SQL: Join two tables on different columns of each table which I had to use string manipulation to achieve the same format for comparison

TABLE dbo_R5PERSONNEL
column PER_DESC
Do, John
Jones, Jacky
TABLE dbo_R5USERS
column USR_DESC
John Do
Jack Jones
Q: How would I join these two tables to get all the USR_DESC from Table dbo_R5USERS that exist in column PER_DESC in Table dbo_R5PERSONNEL.
I used string manipulation to capitalize and extract just the last names from each table
SELECT UCASE(MID(TRIM(dbo_R5USERS.USR_DESC), INSTR(TRIM(dbo_R5USERS.USR_DESC), ' ') + 1, LEN(TRIM(dbo_R5USERS.USR_DESC)) - INSTR(TRIM(dbo_R5USERS.USR_DESC), ' '))) AS LastName
FROM dbo_R5USERS
WHERE dbo_R5USERS.USR_ACTIVE = '+'
ORDER BY dbo_R5USERS.USR_DESC;
SELECT UCASE(MID(TRIM(dbo_R5PERSONNEL.PER_DESC),1,INSTR(TRIM(dbo_R5PERSONNEL.PER_DESC),',')-1)) AS LastName
FROM dbo_R5PERSONNEL
WHERE dbo_R5PERSONNEL.PER_NOTUSED='+'
ORDER BY dbo_R5PERSONNEL.PER_DESC;
How would I incorporate a JOIN on these two subqueries? Is there another method to achieve my desired results?
Thanks in advance!
Update 1:
SELECT R.LastName
, P.LastName FROM
(
SELECT UCASE(MID(TRIM(dbo_R5USERS.USR_DESC)
, INSTR(TRIM(dbo_R5USERS.USR_DESC), ' ') + 1, LEN(TRIM(dbo_R5USERS.USR_DESC)) - INSTR(TRIM(dbo_R5USERS.USR_DESC), ' '))) AS LastName
FROM dbo_R5USERS
WHERE dbo_R5USERS.USR_ACTIVE = '+'
) R
INNER JOIN
(
SELECT UCASE(MID(TRIM(dbo_R5PERSONNEL.PER_DESC),1,INSTR(TRIM(dbo_R5PERSONNEL.PER_DESC),‌​',')-1)) AS LastName
FROM dbo_R5PERSONNEL
WHERE dbo_R5PERSONNEL.PER_NOTUSED='+'
) P
ON R.LastName = P.LastName