Is Pivot my best option? How-To - sql

I have the following table relationships
Location.DeptFK
Dept.PK
Section.DeptFK
Subsection.SectionFK
Question.SubsectionFK
Answer.QuestionFK, SubmissionFK
Submission.PK, LocationFK
one query returns (MainTable)
QuestionNumberVar | Section | Subsection | Question | AnsYes | AnsNo | NA
1-1.1 Math Algebra Did you do your homework? 10 1 1
1-1.2 Math Algebra Did your dog eat it? 9 3 0
2-1.1 English Greek Did you do your homework? 8 0 4
The other returns (Query2)
Answer | Location | QuestionNumberVar | Critical
1 High 1-1.1 1
2 Middle 1-1.1 1
2 High 1-1.2 0
1 Middle 1-1.2 0
0 High 2-1.1 1
1 Elem 2-1.1 1
I want the (Query2) to return (IndividualTable)
QuestionNumberVar | Critical | High | Middle | Ele
1-1.1 1 1 2 'blank'
1-1.2 0 2 1 'blank'
2-1.1 1 0 'blank' 1
I then want to merge it on the end of the previous table using QuestionNumberVar as a key of sorts. so the table will look like
QuestionNumberVar | MainTable | IndividualTable
1-1.1 Data Data
1-1.2 Data Data
2-1.1 Data Data
Where the answers are grouped by QuestionNumberVar. The MainTable is not dynamic but the other IndividualTable needs to be dynamic. Location doesn't always appear for certain Dept's as seen at the relationships.
These Queries work for gathering the required Data but I don't know how to convert them to modify my tables how I would like. I think Pivot is what should be used for Query 2 to make IndividualTable I am also not sure how to mesh IndividualTable with MainTable
MainTable Query
SELECT Section.StepNumber + '-' + Question.QuestionNumber AS QuestionNumberVar,
Question.Question,
Subsection.Name AS Subsection,
Section.Name AS Section,
SUM(CASE WHEN (Answer.Answer = 0) THEN 1 ELSE 0 END) AS NA,
SUM(CASE WHEN (Answer.Answer = 1) THEN 1 ELSE 0 END) AS AnsNo,
SUM(CASE WHEN (Answer.Answer = 2) THEN 1 ELSE 0 END) AS AnsYes,
(select count(distinct Location.Abbreviation) from Department inner join Plant on location.DepartmentFK = Department.PK WHERE(Department.Name = 'insertParameter'))
as total
FROM Department inner join
section on Department.PK = section.DepartmentFK inner JOIN
subsection on Subsection.SectionFK = Section.PK INNER JOIN
question on Question.SubsectionFK = Subsection.PK INNER JOIN
Answer on Answer.QuestionFK = question.PK inner JOIN
Submission on Submission.PK = Answer.SubmissionFK inner join
Location on Location.DepartmentFK = Department.PK AND Location.pk = Submission.PlantFK
WHERE (Department.Name = 'InsertParameter') AND (Submission.MonthTested = '1/1/2017')
GROUP BY Question.Question, QuestionNumberVar, Subsection.Name, Section.Name, Section.StepNumber
ORDER BY QuestionNumberVar;
Query 2
SELECT Answer.Answer, Location.abbreviation, Section.StepNumber + '-' + Question.QuestionNumber AS QuestionNumber, Cast(Question.CriticalProcessVariable AS VARCHAR) AS CriticalProcessVariable
FROM Department left join
Section on Department.PK = Section.DepartmentFK left JOIN
Subsection on Subsection.SectionFK = Section.PK left JOIN
Question on Question.SubsectionFK = Subsection.PK left JOIN
Answer on Answer.QuestionFK = Question.PK left JOIN
Submission on Submission.PK = SubmissionFK left join
Location on Location.DepartmentFK = Department.PK AND Location.pk = Submission.PlantFK
WHERE (Department.Name = 'insertParameter') AND (Submission.MonthTested = '01/01/2017')
ORDER BY CAST(Section.StepNumber as INT) ASC, Question.QuestionNumber;
I have attempted to Pivot Query 2 to no avail. My problem always arises over not being able to sum by Answer because it doesn't recognize it (probably from not being in Location?) I am kind of lost as this is the most complex query I have ever made and I can't wrap my head around the requirements for Pivot and how to properly apply it.

Pivot was the way I handled this eventually working my way through error after error. T/SQL threw a few wrenches in my way. I first Pivoted Query 2
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(PivotQ.Abbreviation)
from ( --QUERY2
) PivotQ
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT StepNumber + ''-'' + QuestionNum as QuestionNumber, '+#cols+' from
(
--Query2
) x
pivot
(
SUM(Answer)
for Abbreviation in (' + #cols + ')
) p
'
Then I used QuestionNumber as a Key to join to MainTable's QuestionNumber. I used a second #cols to make the columns for use in the second query
select #cols2 = STUFF((SELECT distinct ', PivotJoin.' + QUOTENAME(PivotQ.Abbreviation)
from ( --QUERY2
) PivotQ
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
'+ #cols2 +' --added into Select of MainTable
-- Added to From Statement
inner join
('+ #query +') PivotJoin on PivotJoin.QuestionNumber = Section.StepNumber + ''-'' + Question.QuestionNumber
I had to make The Pivot's Question Number the main because now that its T/SQL instead of pure SQL using the Alias in Group By no longer worked. I then added #cols2 to the Group By clause. and made it Order By PivotJoin.QuestionNumber instead.

Related

Use 'Stuff' variable in WHERE clause

So here is the query code we are using:
SELECT
CONVERT(DATE, Nominations.Nomination_Date_Created) AS Nomination_Date_Created,
Nominations.Nomination_Status,
(CASE
WHEN MIN(EPORT.dbo.FDA_Divisions.division_name) = MAX(EPORT.dbo.FDA_Divisions.division_name)
THEN MIN(EPORT.dbo.FDA_Divisions.division_name)
ELSE 'Multiple Divisions'
END) AS Employee_Division,
Nominations.Nomination_Awarded_For,
Nominations.Nomination_Awarded_Other,
Nom.First_Name + ' ' + Nom.Last_Name AS Nominator_Name,
Nominations.Nomination_Group_UUID,
Nominations.Nomination_Group_Name,
Nominations.Nomination_Group_Time_off_Sum,
Nominations.Nomination_Group_Cash_Sum,
Nominations.Nomination_Type,
Nominations.Nomination_Identifier, Nominations.Nomination_Employee_UUID,
Nominations.Nomination_Nominator_ID, Nominations.Nomination_NOAC,
STUFF((SELECT ', ' + NOMGroup.division_name
FROM vw_group_nomination_divisions NOMGroup
WHERE NOMGroup.Nomination_Group_UUID = Nominations.Nomination_Group_UUID
FOR XML PATH('')), 1, 1, '') divList
FROM
Nominations
INNER JOIN
ePort.dbo.Employees AS Employees_1 ON Employees_1.CapHR_ID = Nominations.Nomination_Employee_CapHR_ID
LEFT OUTER JOIN
ePort.dbo.FDA_Offices ON Employees_1.office_id = ePort.dbo.FDA_Offices.office_id
LEFT OUTER JOIN
ePort.dbo.FDA_Centers ON Employees_1.center_ID = ePort.dbo.FDA_Centers.Center_ID
LEFT OUTER JOIN
ePort.dbo.FDA_Divisions ON Employees_1.division_id = ePort.dbo.FDA_Divisions.division_ID
LEFT OUTER JOIN
ePort.dbo.Employees AS Nom ON Nominations.Nomination_Nominator_ID = Nom.CapHR_ID
LEFT OUTER JOIN
ePort.dbo.Employees AS NomAppRTO ON Nominations.Nomination_Approving_Officer_NED_ID = NomAppRTO.CapHR_ID
GROUP BY
CONVERT(DATE, Nominations.Nomination_Date_Created),
Nominations.Nomination_Awarded_For, Nominations.Nomination_Status,
Nominations.Nomination_Awarded_Other,
Nom.First_Name + ' ' + Nom.Last_Name,
Nominations.Nomination_Type, Nominations.Nomination_Group_UUID,
Nominations.Nomination_Group_Name,
Nominations.Nomination_Group_Time_off_Sum,
Nominations.Nomination_Group_Cash_Sum,
Nominations.Nomination_Identifier, Nominations.Nomination_Type,
Nominations.Nomination_Employee_UUID,
Nominations.Nomination_Nominator_ID, Nominations.Nomination_NOAC
HAVING
(Nominations.Nomination_Type = 'Group')
AND (YEAR(CONVERT(DATE, Nominations.Nomination_Date_Created)) IN ('2020'))
ORDER BY
Nomination_Date_Created DESC, Nominations.Nomination_Group_UUID
Output:
| Id | divList |
+--------------------------------------+-------------------+
| 3462BF9B-5056-9C58-994BFFC6A38E7368 | DLR, DTD, OHCM |
| 3B8202C2-5056-9C58-99C591AA86B3A1C9 | OHCM |
| CB5A722C-5056-9C58-9983C1F6C66C0AD7 | DTD, STMD |
And the output is how we need it, however, we need to be able to search it and we cannot get that working. So how does one reference the column 'Name' that the Stuff function creates in the WHERE clause of the query?
We need to do a search within the HAVING OR WHERE clause for a value within the 'divList' column if possible. Such as divList IN ('OHCM').
Anytime I reference 'divList', I get the error:
Invalid column name 'divList'.
This would filter the results to records 1 and 2.
I hope that better explains it.
You don't want the string. Use more basic logic instead:
having sum(case when division_name = 'ccc' then 1 else 0 end) > 0
How is your temp table associated with the view. You need to join your temp table with the nominations view.
SELECT ID,
STUFF((SELECT ', ' + NOMGroup.division_name
FROM vw_group_nomination_divisions NOMGroup
WHERE NOMGroup.Nomination_Group_UUID = nom.Nomination_Group_UUID
FOR XML PATH('')), 1, 1, '') Name
FROM temp1
JOIN vw_group_nomination_divisions nom ON temp1.ID = nom.ID
WHERE Nominations.[Name] = 'ccc'
GROUP by ID

Invalid Column name while running a query

I am new to SQL and I don't know what's wrong in this query,
SELECT
wo.WORKORDERID "Request ID", (wo.CREATEDTIME) "Created on",
aau.FIRST_NAME "Requester", aac.EMAILID 'From',
[To] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wor.Workorderid and wor2.To_cc_bcc='To'
FOR XML PATH('')), 1, 2, ''),
[CC] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wor.Workorderid and wor2.To_cc_bcc='CC'
FOR XML PATH('')), 1, 2, ''),
cd.CATEGORYNAME "Category"
FROM
workorder_recipients wor
LEFT JOIN
workorder wo ON wor.workorderid = wo.workorderid
LEFT JOIN
ModeDefinition mdd ON wo.MODEID = mdd.MODEID
LEFT JOIN
SDUser sdu ON wo.REQUESTERID = sdu.USERID
LEFT JOIN
AaaUser aau ON sdu.USERID = aau.USER_ID
LEFT JOIN
SDUser crd ON wo.CREATEDBYID = crd.USERID
LEFT JOIN
AaaUser cri ON crd.USERID = cri.USER_ID
LEFT JOIN
AaaUserContactInfo aauc ON aau.USER_ID = aauc.USER_ID
LEFT JOIN
AaaContactInfo aac ON aauc.CONTACTINFO_ID = aac.CONTACTINFO_ID
LEFT JOIN
WorkOrderStates wos ON wo.WORKORDERID = wos.WORKORDERID
LEFT JOIN
CategoryDefinition cd ON wos.CATEGORYID = cd.CATEGORYID
WHERE
mdd.MODENAME = 'E-Mail'
AND cd.CATEGORYNAME in ('Agent Operational Technology (EMEA/UK/IE)','Client Technology')
AND wo.IS_CATALOG_TEMPLATE='0'
AND wo.CREATEDTIME >= 1416783600000
AND wo.CREATEDTIME <= 1417388399000
AND wo.ISPARENT='1'
GROUP BY
wo.workorderid
But I keep getting this error:
Column 'workorder_recipients.WORKORDERID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Thanks,
Atul
Imagine the following simple table (T) where ID is the primary key:
ID | Column1 | Column2 |
----|---------+----------|
1 | A | X |
2 | A | Y |
Then you write the following query
SELECT ID, Column1, Column2
FROM T
GROUP BY Column1;
This breaks the SQL Standard, and if it were to run without errors (which it would in MySQL), the result:
ID | Column1 | Column2 |
----|---------+----------|
1 | A | X |
Is no more or less correct than
ID | Column1 | Column2 |
----|---------+----------|
2 | A | Y |
So what you are saying is give me one row for each distinct value of Column1, which both results sets satisfy, so how do you know which one you will get? Well you don't.
For simplicity sake (and the way it is implemented in SQL Server) we state the rule that if an column is not contained in an aggregate function, it must be in the GROUP BY clause for it to appear in the select list. This is not strictly true, the SQL-Standard does allow columns in the select list not contained in the GROUP BY or an aggregate function, however these columns must be functionally dependent on a column in the GROUP BY. From the SQL-2003-Standard (5WD-02-Foundation-2003-09 - page 346) - http://www.wiscorp.com/sql_2003_standard.zip
15) If T is a grouped table, then let G be the set of grouping columns of T. In each contained
in , each column reference that references a column of T shall reference some column C that
is functionally dependent on G or shall be contained in an aggregated argument of a
whose aggregation query is QS.
For example, ID in the sample table is the PRIMARY KEY, so we know it is unique in the table, so the following query conforms to the SQL standard and would run in MySQL and fail in many DBMS currently (At the time of writing Postgresql is the closest DBMS I know of to correctly implementing the standard - Example here):
SELECT ID, Column1, Column2
FROM T
GROUP BY ID;
Since ID is unique for each row, there can only be one value of Column1 for each ID, one value of Column2 there is no ambiguity about
what to return for each row. As far as I know, Postgresql is the only DBMS that has gone anyway to implementing this.
In order for your query to work you would need to add some columns to the GROUP BY:
GROUP BY wo.workorderid, wo.CREATEDTIME, aau.FIRST_NAME, aac.EMAILID, cd.CATEGORYNAME
However, I think you can remove the issue of duplicates by removing workorder_recipients from your FROM, you don't appear to use this anywhere. Removing this reference should remove the need for GROUP BY
SELECT
[Request ID] = wo.WORKORDERID,
[Created on] = wo.CREATEDTIME,
[Requester] = aau.FIRST_NAME,
[From] = aac.EMAILID,
[To] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wo.Workorderid
AND wor2.To_cc_bcc='To'
FOR XML PATH('')), 1, 2, ''),
[CC] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wo.Workorderid
AND wor2.To_cc_bcc='CC'
FOR XML PATH('')), 1, 2, ''),
[Category] = cd.CATEGORYNAME
FROM workorder wo
LEFT JOIN ModeDefinition AS mdd
ON wo.MODEID = mdd.MODEID
LEFT JOIN SDUser AS sdu
ON wo.REQUESTERID = sdu.USERID
LEFT JOIN AaaUser AS aau
ON sdu.USERID = aau.USER_ID
LEFT JOIN SDUser AS crd
ON wo.CREATEDBYID = crd.USERID
LEFT JOIN AaaUser AS cri
ON crd.USERID = cri.USER_ID
LEFT JOIN AaaUserContactInfo AS aauc
ON aau.USER_ID = aauc.USER_ID
LEFT JOIN AaaContactInfo AS aac
ON aauc.CONTACTINFO_ID = aac.CONTACTINFO_ID
LEFT JOIN WorkOrderStates AS wos
ON wo.WORKORDERID = wos.WORKORDERID
LEFT JOIN CategoryDefinition AS cd
ON wos.CATEGORYID = cd.CATEGORYID
WHERE
mdd.MODENAME = 'E-Mail'
AND cd.CATEGORYNAME in ('Agent Operational Technology (EMEA/UK/IE)','Client Technology')
AND wo.IS_CATALOG_TEMPLATE='0'
AND wo.CREATEDTIME >= 1416783600000
AND wo.CREATEDTIME <= 1417388399000
AND wo.ISPARENT='1';
when you use GROUP BY in a query, you need to include every field in the group by which is in the select, except ones where you're aggregating - such as a SUM a MIN or a MAX (Amongst others).
So, to contrive an example, this would be invalid:
SELECT FirstName, LastName, SUM(Score)
FROM HighScores
GROUP BY FirstName
You would also need to include LastName in the GROUP BY to get the sum of a person's scores

SQL Pivot on Foreign Key but display different column header

I had written a stored procedure that would first get a list of columns which were distinct account descriptions and use those to pivot on for getting daily monetary values per account. The problem I encountered is the end user has instances where they have the same Account description for multiple accounts so I am now using AccountID's to pivot on.
Below you will find my query to get Distinct Account ID's and then to create the pivot table. My end goal is that the current column headers for the user are useless i.e. "1504" "1505" "1683" etc. These have no meaning to them. How can I either rename column headers of a result set or somehow use a pivot based on distinct account ID's while displaying a description instead. GLAccounts.Description is the column with the description I would like to display instead of the GLAccounts.AccountID.
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(AccountID)
FROM (
SELECT DISTINCT GLAccounts.AccountID AS AccountID
FROM GeneralLedger
INNER JOIN DailyFiles ON GeneralLedger.DailyFileID = DailyFiles.DailyFileID
Inner Join GLAccounts ON GeneralLedger.AccountID = GLAccounts.AccountID
-- Get All Daily Files for company and date range
INNER JOIN
(SELECT DailyFileID
FROM DailyFiles
WHERE (DailyFiles.DailyFileDate >= CONVERT(DATETIME, #MTDStart, 102)) AND (DailyFiles.DailyFileDate <= CONVERT(DATETIME, #MTDEnd, 102))
AND CompanyID = #CompanyID) AS DAILYFILEIDS ON GeneralLedger.DailyFileID = DAILYFILEIDS.DailyFileID
) x
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = N'SELECT A.*
from(
SELECT SummedAccounts.Date, SUM(SummedAccounts.DayTotal) AS DayTotal, SummedAccounts.AccountID AS AccountID
FROM(SELECT DailyFiles.DailyFileDate AS Date, IIF(GLAccounts.FriendlyName IS NOT NULL AND GLAccounts.FriendlyName <> '''', GLAccounts.FriendlyName, GLAccounts.Description) as AccountDescription, IIF(GeneralLedger.SavedToCredit = 1,
--Saved To Credit Is True
IIF(AccountTYpes.PositiveToCredit = 1, (SUM(GeneralLedger.Credit + GeneralLedger.Debit)), (SUM(GeneralLedger.Credit + GeneralLedger.Debit) * -1)),
--Saved To Credit Is False
IIF(AccountTYpes.PositiveToCredit = 1, ( SUM(GeneralLedger.Credit + GeneralLedger.Debit) * -1), (SUM(GeneralLedger.Credit + GeneralLedger.Debit)))) AS DayTotal, GeneralLedger.SavedToCredit, AccountTypes.PositiveToCredit, GeneralLedger.AccountID AS AccountID
FROM GeneralLedger
INNER JOIN DailyFiles ON GeneralLedger.DailyFileID = DailyFiles.DailyFileID
Inner Join GLAccounts ON GeneralLedger.AccountID = GLAccounts.AccountID
INNER JOIN AccountTypes ON AccountTypes.AccountTypeID = GLAccounts.AccountTypeID
-- Get All Daily Files for company and date range
INNER JOIN
(SELECT DailyFileID
FROM DailyFiles
WHERE (DailyFiles.DailyFileDate >= #MTDStart) AND (DailyFiles.DailyFileDate <= #MTDEnd)
AND CompanyID = #CompanyID) AS DAILYFILEIDS ON GeneralLedger.DailyFileID = DAILYFILEIDS.DailyFileID
GROUP BY GeneralLedger.AccountID, DailyFiles.DailyFileDate, GLAccounts.FriendlyName, GLAccounts.Description, GeneralLedger.SavedToCredit, AccountTypes.PositiveToCredit) SummedAccounts
GROUP BY SummedAccounts.Date, SummedAccounts.AccountID
) y
pivot
(
min(DayTotal)
for AccountID in (' + #cols + ')
) A'
Result Sets Look Like:

concatenate with 3 or 4 joins [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
combine multiple rows int one row with many to many
Using SQL Server I have the following tables/ data
CUS_VISIT
Cus_ID Cus_Vis_ID
1 01
1 02
2 01
and
CUS_EVENT
Cus_Event_ID Cus_ID Cus_Vis_ID
001 1 01
002 1 01
and
CUS_XREF
Cus_ID Cus_Event_ID Cus_Prt_ID Cus_Seq_No
1 001 1 1
1 001 2 1
and
CUS_PRT
Cus_ID Cus_Prt_ID Prt_Cd
1 1 1A
1 2 2A
I am trying to get the following
SQL RESULTS
Cus_ID Prt_Cd Cus_Vis_ID
1 1A,2A 1
what I end up with is
SQL RESULTS
Cus_ID Prt_Cd Cus_Vis_ID
1 1A 1
1 2A 1
The tables are linked by ...
CUS_VISIT.Cus_ID = CUS_EVENT.Cus_ID
CUS_VISIT.Cus_Vis_ID = CUS_EVENT.Cus_Vis_ID
CUS_VISIT.Cus_ID = CUS_XREF.Cus_ID
CUS_EVENT.Cus_Event_ID = CUS_XREF.Cus_Event_ID
CUS_XREF.Cus_Prt_ID = CUS_PRT.Cus_Prt_ID
CUS_XREF.Cus_ID = CUS_PRT.Cus_ID
I can almost get what I am after if I drop the CUS_XREF.Cus_Prt_ID = CUS_PRT.Cus_Prt_ID join but then I get all of the part codes (Prt_Cd) for the customer not just the ones for that visit.
here is what i have
select distinct CUS_EVENT.cus_id, CUS_EVENT.cus_visit_id,
(Select CUS_PRT.prt_cd + ',' AS [text()]
From CUS_PRT, CUS_XREF
where
CUS_EVENT.cus_id=XREF.cus_id
and CUS_EVENT.cus_event_id = XREF.cus_event_id
and CUS_XREF.cus_id=CUS_PRT.cus_id
and CUS_XREF.cus_prt_id = CUS_PRT.cus_prt_id
and CUS_XREF.prt_seq_no ='1'
order by CUS_PRT.prt_cd
for XML PATH('')) [Codes]
from CUS_EVENT
i made a similar post recently but didn't get any specific help. i think i need another sub-query some where. thanks for looking at this.
Well I agree that there's numerous questions about it. You just need to write for xml
select
V.Cus_ID,
V.Cus_Vis_ID,
stuff(
(
select ', ' + TP.Prt_Cd
from CUS_EVENT as TE
inner join CUS_XREF as TX on TX.Cus_Event_ID = TE.Cus_Event_ID and TX.Cus_ID = TE.Cus_ID
inner join CUS_PRT as TP on TP.Cus_Prt_ID = TX.Cus_Prt_ID and TP.Cus_ID = TE.Cus_ID
where
TE.Cus_Vis_ID = V.Cus_Vis_ID and
TE.Cus_ID = V.Cus_ID
for xml path(''), type
).value('.', 'nvarchar(max)')
, 1, 2, '')
from CUS_VISIT as V
SQL FIDDLE
Please try this... But i haven't excuted this query. I have implemented same scenerio. Just try and let me know
SELECT
CUS.Cus_ID
, CUS.Cus_Vis_ID
, Prt_Cd=STUFF(
(SELECT
', ' + S.Prt_Cd
FROM CUS_PRT s
INNER JOIN CUS_XREF XREF ON CUS.cus_id=XREF.cus_id AND s.cus_id=XREF.cus_id AND XREF.Cus_Prt_ID = s.Cus_Prt_ID
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
)
FROM CUS_EVENT CUS
GROUP BY CUS.Cus_ID,CUS.Cus_Vis_ID

How to Optimize this SQL Query?

I have 3 tables:
CRSTasks (ID,parentID)
CRSTaskReceivers (ID,tskID,receiverID)
UserNames (id,name)
...relation between CRSTasks and CRSTaskReceivers one-to-many
between UserNames and CRSTaskReceivers one-to-one
tasks
ID parent
1 null
10 1
50 1
taskReceivers
id taskID receiverID
1 1 4(john)
1 10 2(mike)
1 50 3(brand)
I need result like that:
taskid Receivers
-------------------
1 jone,mike,brand
ONLY FOR PARENT TASKS IT WILL CONCATE RECEIVERS
SQL Server 2005+:
SELECT t.id AS taskid,
STUFF((SELECT ','+ x.name
FROM (SELECT COALESCE(pu.[ArabicName], aut.Name) AS name
FROM CRSTaskReceivers tr
JOIN AD_USER_TBL aut ON aut.id = tr.receiverid
LEFT JOIN PORTAL_USERS pu ON pu.id = aut.id
WHERE tr.crstaskid = t.id
AND tr.receivertype = 1
UNION
SELECT agt.name
FROM CRSTaskReceiver tr
JOIN AD_GROUP_TBL sgt ON agt.id = tr.receiverid
WHERE tr.receivertype = 3
AND tr.crstaskid = t.id) x
FOR XML PATH('')), 1, 1, '')
FROM CRSTasks t
Don't need the function.
Besides the odd string concatenation going on it sure looks like all that could be done in one query instead of four. It's perfectly fine to have more than one criteria in a join. Something along:
FROM CRSTaskReceiver
INNER JOIN CRSTask
ON CRSTaskReceiver.CRSTaskID = CRSTask.ID
INNER JOIN CRS_BuiltinGroup
ON CRSTaskReceiver.ReceiverID = CRS_BuiltinGroup.ID AND CRSTaskReceiver.ReceiverType = 4
WHERE CRSTask.ParentTask = #TaskID
Also the below part of the function seems to do absolutely nothing. What is it meant to do?
DECLARE #tmpLength INT
SET #tmpLength = 0
SET #tmpLength = LEN(#tmp)
IF #tmpLength > 0
BEGIN
SET #tmp = SUBSTRING(#tmp, 0, #tmpLength)
END