(Group By) & (FOR XML PATH) & JOIN - sql

Is there any other approch rather than saving the result of joining (the Table #VT & TableA ) in one Table variable and then from there make the Grouping
select ID ,
STUFF (( select distinct ' / ' + TA.Reason
from #VT
where ( ID = VT.ID )
for xml path(''),TYPE).value('(./text())[1]','VARCHAR(MAX)') ,1,2,'' ) as XXX
from #VT as VT
join TableA as TA on ( TA.ID = VT.ID)
group by ID
I get this Error
Column 'TableA.Reason' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

I would go with DISTINCT instead of GROUP BY :
SELECT DISTINCT ID,
STUFF (( SELECT DISTINCT ' / ' + ta.Reason
FROM TableA ta
WHERE vt.ID = ta.ID
FOR XML PATH (''),TYPE).VALUE('(./text())[1]','VARCHAR(MAX)'
), 1, 2, ''
) AS XXX
FROM #VT vt;

I think you have the tables in the wrong place. Does this work?
select ID ,
stuff(( select distinct ' / ' + TA.Reason
from TableA TA
where vt.ID = ta.ID
for xml path(''), TYPE
).value('(./text()) [1]', 'VARCHAR(MAX)') , 1, 2, ''
) as XXX
from #VT vt ;

Related

SQL Query (STUFF)

This is what I did:
SELECT
[tbl_flw].[question_id], [tbl_flw].[project_id],
[tbl_flw].[follow_up_ans], [tbl_flw].[follow_up_ques],
[t1].[question] AS current_ques,
[t2].[question] AS followUp_ques,
displayname = STUFF((SELECT ', ' + [tbl_ques].[question]
FROM [tbl_flw]
LEFT JOIN [tbl_ques] ON [tbl_ques].[question_id] = [tbl_flw].[follow_up_ques]
WHERE [tbl_flw].[follow_up_ques] = [tbl_ques].[question_id]
FOR XML PATH('')), 1, 2, '')
FROM
[tbl_flw]
INNER JOIN
[tbl_ques] t1 ON t1.question_id = [tbl_flw].[question_id]
INNER JOIN
[tbl_ques] t2 ON t2.question_id = [tbl_flw].[follow_up_ques]
WHERE
[project_id] = 162
This is the result
This is how I want:
But I'm trying to put it like this:
How to change the SQL query so it will be like result above (displayname column)
I can't copy your sql code so I'll give you some example.
If you want to concat columns by group you can use GROUP_CONCAT function like this
SELECT pub_id,GROUP_CONCAT(cate_id)
FROM book_mast
GROUP BY pub_id;
If you want to use a seperator
SELECT pub_id,GROUP_CONCAT(cate_id SEPERATOR ',')
FROM book_mast
GROUP BY pub_id;
And if you want to order the group and use concat unique values
SELECT pub_id,GROUP_CONCAT(DISTINCT cate_id ORDER BY cate_id ASC SEPERATOR ',')
FROM book_mast
GROUP BY pub_id;
edit : this should work
SELECT [tbl_flw].[question_id], [tbl_flw].[project_id], [tbl_flw].[follow_up_ans],
[tbl_flw].[follow_up_ques], [t1].[question] AS current_ques, [t2].[question] AS followUp_ques,
displayname = STUFF((SELECT ', ' + [tbl_ques].[question] FROM [tbl_flw]
LEFT JOIN [tbl_ques] ON [tbl_ques].[question_id] = [tbl_flw].[follow_up_ques]
WHERE[tbl_flw].[follow_up_ques] = [tbl_ques].[question_id] AND [t1].[question] = [tbl_ques].[question] FOR XML PATH('')), 1, 2, '')
FROM [tbl_flw]
INNER JOIN [tbl_ques] t1 ON t1.question_id = [tbl_flw].[question_id]
INNER JOIN [tbl_ques] t2 ON t2.question_id = [tbl_flw].[follow_up_ques]
WHERE [project_id] = 162

Returning comma separated values in SQL Server in one element

I have the below query which I am using to return comma separated result.
SELECT STUFF
(
(
SELECT ',' + em.EMAIL
FROM(
SELECT DISTINCT USR.EMAIL AS EMAIL
FROM PRNCPLS A, PRNCPLS B, USER_INFO USR,
RELATIONSHIPS C
WHERE A.ID = C.PARENTID
AND B.ID = C.CHILDID
AND A.TYPE = 'USER' and B.TYPE = 'ROLE'
AND A.ID = USR.ID
and B.NAME = 'Approver'
AND USR.EMAIL IS NOT NULL) em
ORDER BY em.EMAIL FOR XML PATH('')
),
1, 1, ''
) AS Output
I have a requirement to update this query in a way that the first line of the SQL statement (and not the output) always start like this
SELECT EMAIL FROM
This is required since the tool I am using for some reason expects FROM in the first line and just one single element in the SELECT clause. My query actually only returns one element, so I was hoping to somehow update it.
Expected output - abcd#gmail.com,1234#yahoo.com,xyz#gmail.com
Any help would be appreciated.
SELECT EMAIL FROM (
SELECT STUFF
(
(
SELECT ',' + em.EMAIL
FROM(
SELECT DISTINCT USR.EMAIL AS EMAIL
FROM PRNCPLS A, PRNCPLS B, USER_INFO USR,
RELATIONSHIPS C
WHERE A.ID = C.PARENTID
AND B.ID = C.CHILDID
AND A.TYPE = 'USER' and B.TYPE = 'ROLE'
AND A.ID = USR.ID
and B.NAME = 'Approver'
AND USR.EMAIL IS NOT NULL) em
ORDER BY em.EMAIL FOR XML PATH('')
),
1, 1, '') AS EMAIL
) AS Output
Beware of both "...EMAIL...":
"SELECT EMAIL ..."
"...1,1,'') AS EMAIL...".
have you tried
SELECT 'SELECT EMAIL FROM ' + STUFF
(
(
SELECT ',' + em.EMAIL
FROM(
SELECT DISTINCT USR.EMAIL AS EMAIL
FROM PRNCPLS A, PRNCPLS B, USER_INFO USR,
RELATIONSHIPS C
WHERE A.ID = C.PARENTID
AND B.ID = C.CHILDID
AND A.TYPE = 'USER' and B.TYPE = 'ROLE'
AND A.ID = USR.ID
and B.NAME = 'Approver'
AND USR.EMAIL IS NOT NULL) em
ORDER BY em.EMAIL FOR XML PATH('')
),
1, 1, ''
) AS Output;
or is there more to how the data is formatted?
Have you tried doing
SELECT 'SELECT EMAIL FROM '
UNION
... Your existing query
You can wrap almost any SELECT like this:
SELECT t.SomeColumn FROM
(
place your existing SELECT here
) t;
This would not work with a CTE-query, but CTEs can be shifted into sub-queries themselves.
Hint: Try to avoid old-fashioned JOINs if possible. There is a good link provided by Sami in the comments...

Trying to join two sql statement

I would like to join Query 1 and Query 2 on TripId.
Query 1
SELECT tblTrips.TripId,tblVehicles.VehicleNo
FROM tblTrips INNER JOIN tblVehicles ON tblTrips.VehicleId = tblVehicles.VehicleId
Query 2
;with T1 as (
SELECT tblTrips.TripId, tblTripDeductions.Amount, CONVERT(VARCHAR(400),tblDeductionTypes.DeductionType+' - '+tblTripDeductions.Description+' - '+ CONVERT(VARCHAR(24),tblTripDeductions.Amount)) as DeductionFor
FROM tblTrips INNER JOIN
tblTripDeductions ON tblTrips.TripId = tblTripDeductions.TripId INNER JOIN
tblDeductionTypes ON tblTripDeductions.DeductionId = tblDeductionTypes.DeductionId
)select **T1.TripId**, SUM(T1.Amount) as Amount, stuff((select '#',' ' + CONVERT(varchar(1000),T2.DeductionFor) from T1 AS T2 where T1.TripId = T2.TripId for xml path('')),1,1,'') [Description] from T1
Group by TripId
First query's output is list of TripId and VehicleNo.
Second query's output is list of TripId, Amount and description.
And my desire output is TripId, VehicleNo, amount and description.
The Syntax for WITH (Common Table Expressions) allows you to create multiple CTE's.
Using that you can turn your final part of Query2 in to a CTE (Which I'll name Query2) and your query for Query1 can also be made in to a CTE (which I'll name Query1).
Then, the final SELECT statement can simply join those two CTE's together.
;
WITH
T1 as (
SELECT tblTrips.TripId, tblTripDeductions.Amount, CONVERT(VARCHAR(400),tblDeductionTypes.DeductionType+' - '+tblTripDeductions.Description+' - '+ CONVERT(VARCHAR(24),tblTripDeductions.Amount)) as DeductionFor
FROM tblTrips INNER JOIN
tblTripDeductions ON tblTrips.TripId = tblTripDeductions.TripId INNER JOIN
tblDeductionTypes ON tblTripDeductions.DeductionId = tblDeductionTypes.DeductionId
)
,
Query2 AS (
select **T1.TripId**, SUM(T1.Amount) as Amount, stuff((select '#',' ' + CONVERT(varchar(1000),T2.DeductionFor) from T1 AS T2 where T1.TripId = T2.TripId for xml path('')),1,1,'') [Description] from T1
Group by TripId
)
,
Query1 AS (
<Your Code For Query1>
)
SELECT
*
FROM
Query1
INNER JOIN
Query2
ON Query1.TripID = Query2.TripID
I haven't don't anything to check your queries, as the layout that you have used isn't very readable.
Just merge the queries using CTE (didn't change/review your code, just formatted it for the sake of readability - input was pretty horrible to read)
;WITH T1 AS (
SELECT tblTrips.TripId
, tblTrips.DestinationDistrictId
, tblTrips.VehicleId
, tblTrips.No
, tblVehicles.VehicleNo
, tblTrips.CoachNo
, CONVERT(VARCHAR(24), tblTrips.GoDate, 105) AS GoDate
, tblTrips.GoTime
, CASE WHEN tblTrips.IsCome=1
THEN CONVERT(VARCHAR(24), tblTrips.ComeDate, 105)
ELSE '-'
END AS ComeDate
, CASE WHEN tblTrips.IsCome=1
THEN tblTrips.ComeTime
ELSE '-'
END AS ComeTime
, CASE WHEN tblTrips.IsCome=1
THEN (SD.DistrictName + ' - ' + DD.DistrictName + ' - ' + SD.DistrictName)
ELSE (SD.DistrictName + ' - ' + DD.DistrictName)
END AS Destination
, tblSupervisors.Name AS Supervisor
, tblDrivers.Name AS Driver
, tblTrips.AdvanceAmount
, tblTrips.AdvanceDescription
FROM tblTrips
INNER JOIN tblSupervisors ON tblTrips.SuperVisorId = tblSupervisors.SupervisorId
INNER JOIN tblDrivers ON tblTrips.DriverId = tblDrivers.DriverId
INNER JOIN tblDistricts SD ON tblTrips.StartDistrictId = SD.DistrictId
INNER JOIN tblDistricts DD ON tblTrips.DestinationDistrictId = DD.DistrictId
INNER JOIN tblVehicles ON tblTrips.VehicleId = tblVehicles.VehicleId
)
, Q1 AS (
SELECT T1.TripId
, SUM(T1.Amount) AS Amount
, STUFF((
SELECT '#', ' ' + CONVERT(VARCHAR(MAX), T2.DeductionFor)
FROM T1 AS T2
WHERE T1.TripId = T2.TripId FOR XML PATH(''))
,1,1,'') AS [Description]
FROM T1
GROUP BY TripId
)
, Q2 AS (
SELECT tblTrips.TripId
, tblTripDeductions.Amount
, CONVERT(VARCHAR(400), tblDeductionTypes.DeductionType + ' - ' + tblTripDeductions.Description + ' - ' + CONVERT(VARCHAR(24), tblTripDeductions.Amount)) AS DeductionFor
FROM tblTrips
INNER JOIN tblTripDeductions ON tblTrips.TripId = tblTripDeductions.TripId
INNER JOIN tblDeductionTypes ON tblTripDeductions.DeductionId = tblDeductionTypes.DeductionId
)
SELECT *
FROM Q1
INNER JOIN Q2 ON Q1.TripId = Q2.TripId

why are the results of the two queries different

the first query:
SELECT u.id , prop1.id
FROM ( SELECT '9fbc6e9b59504c08ac643752c1e2d033' AS id ,
'|6813dbbfec6241a19b8d2316d2cb2a65,1|' AS customprop
UNION
SELECT 'f2271c45682f45fc84527c4afff0ab16' AS id ,
'|6813dbbfec6241a19b8d2316d2cb2a65,2|' AS customprop
) u
INNER JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY a.Id ) id ,
A.Id propId ,
B.NAME
FROM ( SELECT '6813dbbfec6241a19b8d2316d2cb2a65' AS id ,
CONVERT(XML, '<v>1,职业资格1</v><v>2,职业资格2</v>') AS value
) A
OUTER APPLY ( SELECT Name = N.v.value('.',
'nvarchar(Max)')
FROM A.[VALUE].nodes('/v') N ( v )
) B
) prop1 ON CHARINDEX('|' + prop1.propid + ','
+ CONVERT(NVARCHAR(10), prop1.id)
+ '|', u.customprop) > 0
GROUP BY u.id ,
prop1.id
the second query:
SELECT u.id ,prop1.id, count(*)
FROM ( SELECT '9fbc6e9b59504c08ac643752c1e2d033' AS id ,
'|6813dbbfec6241a19b8d2316d2cb2a65,1|' AS customprop
UNION
SELECT 'f2271c45682f45fc84527c4afff0ab16' AS id ,
'|6813dbbfec6241a19b8d2316d2cb2a65,2|' AS customprop
) u
INNER JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY a.Id ) id ,
A.Id propId ,
B.NAME
FROM ( SELECT '6813dbbfec6241a19b8d2316d2cb2a65' AS id ,
CONVERT(XML, '<v>1,职业资格1</v><v>2,职业资格2</v>') AS value
) A
OUTER APPLY ( SELECT Name = N.v.value('.',
'nvarchar(Max)')
FROM A.[VALUE].nodes('/v') N ( v )
) B
) prop1 ON CHARINDEX('|' + prop1.propid + ','
+ CONVERT(NVARCHAR(10), prop1.id)
+ '|', u.customprop) > 0
GROUP BY u.id ,
prop1.id
sql can be executed on sqlserver 2005 directly.
the first query can produce one item and the second query produce two items.
I think that the two queries should both produce two items.
I have thouht for three days and I really want to konw why.
I'm a Chinese and my English is poor.I hope you can understand my description
Tough question, but the problem is with this line:
INNER JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY a.Id ) id ,
The ORDER BY is ambiguous and consequently, if it is executed multiple times (which it can be because of the INNER JOIN it is contained in), it may not always return the same ordering/assignment. This can cause a latter join condition to only match on one record instead of two, which is what happens in the query plan being used for the version without the count(*) column.
To fix this, you just need to add something to make the ordering assignment unique, like this:
INNER JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY a.Id, B.Name ASC ) id ,
Try it like this, it should work.
Your problem is with the ORDER BY clause of the ROW_NUMBER - since the a.ID is not unique the outcome is unpredictable. Make that unique and your problem will go away - you can use something like
...SELECT ROW_NUMBER() OVER ( ORDER BY newid() ) id...

How can I use Sql to Order By This Statement?

How can I order the list 'widgets_spec by number of widgets?
select distinct
m.p_c_id
,(select distinct '<li>' +convert(varchar,widgets) + '<br> '
from dbo.spec_master m2
where m.p_c_id = m2.p_c_id and widgets is not null
for xml path(''), type).value('.[1]', 'nvarchar(max)'
) as widgets_spec
from dbo.spec_master m
inner join dbo.ProductVaration pv on pv.p_c_id = m.p_c_id
inner join dbo.Varation v on v.varation_id = pv.varation_type_id
where v.varation_id = 4
group by m.p_c_id
Right now output looks like:
<li>10<br> <li>12<br> <li>15<br> <li>8<br>
When I want it to look like:
<li>8<br> <li>10<br> <li>12<br> <li>15<br>
Thanks for your help.
EDIT: I'm trying to order the internal select statement that concatenates the values.
You do not need both Distinct and Group By. You should use one or the other. In this case, I believe you have to use Group By for it to work.
Select m.p_c_id
, (
Select '<li>' + Cast( m2.num_of_lights As varchar(10)) + '<br /> '
From dbo.spec_master As m2
Where m.p_c_id = m2.p_c_id
And m2.num_of_lights Is Not Null
Group By m2.num_of_lights
Order By m2.num_of_lights
For Xml Path(''), type).value('.[1]', 'nvarchar(max)'
) As numLights_spec
From dbo.spec_master As m
Inner Join dbo.ProductVaration As pv
On pv.p_c_id = m.p_c_id
Inner Join dbo.Varation As v
On v.varation_id = pv.varation_type_id
Where v.varation_id = 4
Group by m.p_c_id
select distinct
m.p_c_id
,(select distinct '<li>' +convert(varchar,num_of_lights) + '<br> '
from dbo.spec_master m2
where m.p_c_id = m2.p_c_id and num_of_lights is not null
ORDER BY convert(varchar,num_of_lights)
) as numLights_spec
from dbo.spec_master m
inner join dbo.ProductVaration pv on pv.p_c_id = m.p_c_id
inner join dbo.Varation v on v.varation_id = pv.varation_type_id
where v.varation_id = 4
group by m.p_c_id
) As SubA
Some of the other answers here won't work, since ordering by the now-varchar num_of_lights will put '8' after '15' as is happening now. You want to order the numLights numerically, which isn't going to happen with those html tags around them. You can add a subselect to your subselect so that you order them, then select them with the tags around them. Example (not tested):
SELECT * FROM (
select distinct
m.p_c_id
,(select distinct '<li>' +convert(varchar,num_of_lights) + '<br> '
from (select distinct p_c_id, num_of_lights from dbo.spec_master order by num_of_lights) m2
where m.p_c_id = m2.p_c_id and num_of_lights is not null
for xml path(''), type).value('.[1]', 'nvarchar(max)'
) as numLights_spec
from dbo.spec_master m
inner join dbo.ProductVaration pv on pv.p_c_id = m.p_c_id
inner join dbo.Varation v on v.varation_id = pv.varation_type_id
where v.varation_id = 4
group by m.p_c_id
Personally, I'd just add the html tags in whatever back-end code is getting the result of the query.