How to get my STUFF Function to work in SQL Server - sql-server

I am attempting the following query in SQL Server:
SELECT AlertID,
(STUFF((SELECT ', ' + t2.LocationDesc
FROM app_Location t2
WHERE t1.LocationCode = t2.LocationCode
FOR XML PATH (''))
, 1, 1, '')) as Location,
CensusTime,
InsertDate
FROM MultiCensusEmail
INNER JOIN app_Location t1 ON MultiCensusEmail.Location = t1.LocationCode
I want it to return a comma delimited list for the locations, but they are showing up on separate rows.
I want the row to end up something like this:
5A8056A7-5D8F-4678-B980-9E54987EE70C | AS EMERGENCY DEPT, BN CARDIAC,
BN CHEST PAIN UNIT | 7:00 | 2016-10-17 9:17:55.067

You don't provide much detail about your data, but I think that your JOIN is not needed.
SELECT AlertID,
(STUFF((SELECT ', ' + t2.LocationDesc
FROM app_Location t2
WHERE MultiCensusEmail.Location = t2.LocationCode // probably you want another condition here
FOR XML PATH (''))
, 1, 1, '')) as Location,
CensusTime,
InsertDate
FROM MultiCensusEmail
What do you want to "group by" (e.g. what data item does have multiple locations)?
The "outer" query should produce the wanted rows without "location" (in your case), and the "inner" FOR XML query should have a condition that filters the "locations" you want to have comma-separated.

I was able to accomplish what I wanted to do using COALESCE:
declare #Location varchar(max)
select #Location = COALESCE(#Location + ', ', '') + LocationDesc
From app_Location INNER JOIN MultiCensusEmail ON MultiCensusEmail.Location = app_Location.LocationCode
where upper(UserID) = 'test'
select distinct AlertID, #Location, CensusTime, InsertDate
from MultiCensusEmail
where upper(UserID) = 'test'

Related

Filter Results From 'STUFF' Function

I need to filter the results from my STUFF function which are held in the column 'combined_ops'. I need to only see records that do not contain the word 'Transfer'. I've tried the classic WHERE combined_ops NOT LIKE '%transfer%', but does not work. See my code and results and please let me know where I went wrong. Thank You.
SELECT Job, STUFF((SELECT DISTINCT ' ' + Operation_Service
FROM dbo.Job_Operation
WHERE dbo.Job_Operation.Job = dbo.Job.Job
for xml path('')),1,2,'') AS combined_ops
FROM dbo.Job
WHERE dbo.Job.Status = 'Active'
AND dbo.Job.Customer_PO = 'tmi stock'
enter image description here
There are a few ways to do this.
You can put the FOR XML in a CROSS APPLY and filter afterwards
SELECT
j.Job,
jo.combined_ops
FROM dbo.Job j
CROSS APPLY (SELECT
STUFF((SELECT DISTINCT ' ' + jo.Operation_Service
FROM dbo.Job_Operation jo
WHERE jo.Job = j.Job
for xml path(''), type
).value('text()[1]','nvarchar(max)'),1,2,'')
) AS jo(combined_ops)
WHERE j.Status = 'Active'
AND j.Customer_PO = 'tmi stock'
AND jo.combined_ops NOT LIKE '%transfer%'
Or you can use HAVING and conditional aggregation
SELECT Job,
STUFF((
SELECT ' ' + jo.Operation_Service
(
SELECT jo.Operation_Service
FROM dbo.Job_Operation jo
WHERE jo.Job = j.Job
GROUP BY jo.Operation_Service
HAVING COUNT(CASE WHEN jo.Operation_Service LIKE '%transfer%' THEN 1 END) = 0
) jo
for xml path(''), type
).value('text()[1]','nvarchar(max)'),1,2,'') AS combined_ops
FROM dbo.Job j
WHERE j.Status = 'Active'
AND j.Customer_PO = 'tmi stock'
Note the use of the syntax for xml path(''), type).value('text()[1]','nvarchar(max)') to unescape XML characters correctly.
Note also the use of table aliases rather than three part column names.

Arrow(-->) does not show in SQL Server SELECT when use as xml path

I am trying to get all route path separating with arrow (-->). But the arrow (-->) does not work, it is shown as -->.
SELECT
vrmd.LocationName + '--> '
FROM
dbo.tbl_VehicleRouteMapDetail vrmd
WHERE
vrmd.VrmapId = 1
ORDER BY
vrmd.VrmapId
FOR XML PATH('')
But it's working perfectly this way:
DECLARE #Route VARCHAR(MAX)= ''
SELECT #Route = #Route + vrmd.LocationName + '--> '
FROM dbo.tbl_VehicleRouteMapMaster vrmm
INNER JOIN dbo.tbl_VehicleRouteMapDetail vrmd ON vrmd.VrmapId = vrmm.VrmapId
ORDER BY vrmd.VrmapDetailId ASC
Why choose first query?
I need to use this query as subquery. In this case second query does not work for me:
SELECT
COUNT(ewva.VehicleId) Allocation, vii.Capacity,
STUFF((SELECT vrmd.LocationName + '=> '
FROM dbo.tbl_VehicleRouteMapDetail vrmd
WHERE vrmd.VrmapId = vrmm.VrmapId
ORDER BY vrmd.VrmapId
FOR XML PATH('')), 1, 1, '') AS name_csv
FROM
dbo.tbl_VehicleInfoInternal vii
INNER JOIN
dbo.tbl_EmpWiseVehicleAllocation ewva ON ewva.VehicleId = vii.VehicleId
INNER JOIN
dbo.tbl_VehicleRouteMapMaster vrmm ON vrmm.VehicleId = vii.VehicleId
GROUP BY
ewva.VehicleId, vii.Capacity, vrmm.VrmapId
Any help would be appreciated.
It's as simple as adding the TYPE directive to your FOR XML clause (docs here). This will return the result as an instance of the XML type rather than text. Text will have certain characters (e.g. > and <) translated (> and <) to fit within an XML element.
SELECT
vrmd.LocationName + '--> '
FROM
dbo.tbl_VehicleRouteMapDetail vrmd
WHERE
vrmd.VrmapId = 1
ORDER BY
vrmd.VrmapId
FOR XML
PATH(''), TYPE

Query taking a long time in SQL Server

The below query taking more time to give results. This query in running inside the exists clause and also this query having stuff function.Is there any way to optimize or rewrite this query?.
AND EXISTS(SELECT 1
FROM
(SELECT DISTINCT
F_ALIAS,
F_DATA_CODE,
STUFF((SELECT ', ' + A.F_DATA
FROM T_REP_DATA A
WHERE A.F_ALIAS = RPDS.F_ALIAS
AND A.F_DATA_CODE = RPDS.F_DATA_CODE
AND '1:WVTST{PROD006' = A.F_ALIAS
FOR XML PATH(''), TYPE).value( '.', 'NVARCHAR(MAX)'), 1, 2, '') F_DATA
FROM T_REP_DATA RPDS
INNER JOIN
(SELECT DISTINCT F_CUSTOM2
FROM T_MSDSTYPES
WHERE (F_CUSTOM2 IS NOT NULL AND F_CUSTOM2 != '')) MT ON MT.F_CUSTOM2 = RPDS.F_DATA_CODE and RPDS.F_ALIAS = '1:WVTST{PROD006') RPDS_CUSTOM2)
WHERE RPDS_CUSTOM2.F_DATA LIKE 'MANU'
Your query is probably not correct at all (LIKE 'MANU' actually means = 'MANU'), but perhaps your query is doing (or is supposed to be doing) nothing more than this:
AND EXISTS(
SELECT 1
FROM T_REP_DATA RPDS
INNER JOIN T_MSDSTYPES MT
ON MT.F_CUSTOM2 = RPDS.F_DATA_CODE
WHERE RPDS.F_ALIAS = '1:WVTST{PROD006'
AND RPDS.F_DATA = 'MANU'
)
more specific answer requires more details.

SQL: How to CONCAT value

How can I return the values of MainEmail in the query below, delimited by commas and still count MDCselect?
declare #MainHospital varchar(50)='hospital 1'
select distinct mainhospital , f.Item, count(*) Count
from SurveyPicList s
cross apply splitstrings(s.MDCselect,':') as f
WHERE MainHospital = #MainHospital
GROUP BY MainHospital, f.Item
ORDER BY Count DESC
To be clear the above returns this: http://i.imgur.com/F1oPU6P.jpg
So there were 3 separate entries/people that selected "02-Eye". I want to list out their emails(MainEmail) comma delimited. Please let me know if I am unclear.
Assuming from your use of CROSS APPLY that you are using SQL Server, and that it is at least version 2005, you can use XML to do the concatenation as follows:
declare #MainHospital varchar(50)='hospital 1';
select mainhospital , f.Item, count(*) Count
,Stuff(
(select distinct ', ' + m.MainEmail
from SurveyPicList m
where m.MainHospital = #MainHospital
and ':' + m.MDCselect + ':' like '%:' + f.Item + ':%'
FOR XML PATH ('')),
1, 2, '') as Emails
from SurveyPicList s
cross apply splitstrings(s.MDCselect,':') as f
WHERE MainHospital = #MainHospital
GROUP BY MainHospital, f.Item
ORDER BY Count DESC
From the name I am assuming that splitstrings splits its first argument into items separated by its second argument. Hence I used like to check for f.Item in m.MDCselect in the WHERE condition of the subselect. Actually, what this WHERE condition is doing is collecting all the rows from another instance of the same table that match one record in the final grouped output.

TSQL query for tree view control and remove empty elements from an xml file

Query for treeview control, sometimes contains empty elements which throws an exception (when there are no attributes in an element) due to data-binding of the control the text values is set to "GrandChildOfFirstRow"
I did get rid of them in my query via xquery but is there an alternative way to doing this or a better smarter way to get rid of those empty elements, (I need the left outer join for proper records for this query) or is it possible to combine the xquery code into shorter code:
Query:
declare #x as xml
set #x =
(
SELECT distinct
Table1.AssetObjID, Table1.Asset_ID , Table1.FromLR, Table1.AssetType + ', ' + Table1.StreetName + ', ' + Table1.FromMunicNo as FirstRow,
Table2.ACIObjID ,Table2.PAssetObjID, Table2.Feature_ID + ', ' + Table2.FeatureName AS ChildOfFirstRow,
Table3.ITMObjID ,Table3.Item_ID + ',' + Table3.[DESC] as GrandChildOfFirstRow
FROM Table1 left outer join
Table2 ON Table1.AssetObjID = Table2.PAssetObjID left outer join
Table3 ON Table1.AssetObjID = Table3.AssetObjID AND Table2.ACIObjID = Table3.ACIObjID
where Table1.AssetType ='xxxx'
for xml auto,root('xml')
)
--what it does is it only grabs one empty element and deletes only occurrences of that
--specific element for the whole file
--so If I have 2 or more elements which are empty in an xml file
--I will have to repeat that code each time
SET #x.modify('delete //*[not(node()) and not(./#*)]')
SET #x.modify('delete //*[not(node()) and not(./#*)]')
You can use for xml path() and build your nested levels with correlated sub-queries.
select Table1.AssetObjID as "#AssetObjID",
Table1.Asset_ID as "#Asset_ID",
Table1.FromLR as "#FromLR",
Table1.AssetType + ', ' + Table1.StreetName + ', ' + Table1.FromMunicNo as "#FirstRow",
(
select Table2.ACIObjID as "#ACIObjID",
Table2.PAssetObjID as "#PAssetObjID",
Table2.Feature_ID + ', ' + Table2.FeatureName AS "#ChildOfFirstRow",
(
select Table3.ITMObjID as "#ITMObjID",
Table3.Item_ID + ',' + Table3.[DESC] as "#GrandChildOfFirstRow"
from Table3
where Table1.AssetObjID = Table3.AssetObjID and
Table2.ACIObjID = Table3.ACIObjID
for xml path('Table3'), type
)
from Table2
where Table1.AssetObjID = Table2.PAssetObjID
for xml path('Table2'), type
)
from Table1
where Table1.AssetType = 'xxxx'
for xml path('Table1'), root('xml')

Resources