I have this query which runs fine and with no problem!
SELECT [Q].sHost
, LEFT([Q].sDescription, Len([Q].sDescription) - 1) AS [sDescription]
FROM (
SELECT DISTINCT [Q2].sHost
, (
SELECT CONVERT(NVARCHAR(MAX), [Q1].[sDescription]) + N', ' AS [text()]
FROM (
SELECT (
CASE
WHEN (CHARINDEX('\', [sInstance]) = 0)
THEN [sInstance]
ELSE substring([sInstance], 0, CHARINDEX('\', [sInstance]))
END
) AS sHost
, [sDescription]
FROM [db_group].[dbo].[instanceCommentsList]
) AS [Q1]
WHERE ([Q1].sHost = [Q2].sHost)
FOR XML PATH('')
) [sDescription]
FROM (
SELECT (
CASE
WHEN (CHARINDEX('\', [sInstance]) = 0)
THEN [sInstance]
ELSE substring([sInstance], 0, CHARINDEX('\', [sInstance]))
END
) AS sHost
, [sDescription]
FROM [db_group].[dbo].[instanceCommentsList]
) AS [Q2]
) AS [Q]
when I save this query as a view, I get the following error
Error in WHERE clause near '('.
Error in WHERE clause near '='. Unable
to parse query text.
not sure where is the problem!
it's saves any way and it kind of works, I can use it in a simple select query but I get a red line under the name of the view and when I put the mouse over I get this message
The object name is invalid ....
and if I use it in a more complex query it does not work at all
EDIT:----------------------------------
after reading Cannot get FOR XML PATH to work thanks to SelectDistinct's comment
I fixed it but still get one more error!
Error in WHERE clause near '('.
Unable to parse query text.
here is the fixed code:
SELECT [Q].sHost
, LEFT([Q].sDescription, Len([Q].sDescription) - 1) AS [sDescription]
FROM (
SELECT DISTINCT [Q2].sHost
, (
SELECT CONVERT(VARCHAR(MAX), [Q1].[sDescription]) + ', ' AS [text()]
FROM (
SELECT (
CASE
WHEN (CHARINDEX('\', [sInstance]) = 0)
THEN [sInstance]
ELSE substring([sInstance], 0, CHARINDEX('\', [sInstance]))
END
) AS sHost
, [sDescription]
FROM [db_group].[dbo].[instanceCommentsList]
) AS [Q1]
WHERE ([Q1].sHost = [Q2].sHost)
FOR XML PATH(''), type
).value('.', 'varchar(max)') as [sDescription]
FROM (
SELECT (
CASE
WHEN (CHARINDEX('\', [sInstance]) = 0)
THEN [sInstance]
ELSE substring([sInstance], 0, CHARINDEX('\', [sInstance]))
END
) AS sHost
, [sDescription]
FROM [db_group].[dbo].[instanceCommentsList]
) AS [Q2]
) AS [Q]
Try WHERE [Q1].sHost = [Q2].sHost instead of WHERE ([Q1].sHost = [Q2].sHost) .
Related
I'd like to put together only unique values in the concatenated string. My code is currently:
select rc.Routage
, COUNT(distinct rc.Event)
, STUFF((select ', ' + cast(rcA.Event as varchar)
from Receiving rcA
where rcA.supplier = 'user'
for xml path(''))
, 1, 1, '')
from Receiving rc
where rc.supplier = 'user'
group by rc.Routage
order by COUNT(distinct rc.Event)desc
This gives me the output I'd expect, but I would like to eliminate the duplicate values in the stuff/for xml path field.
I've tried various combinations of distinct and group by in the stuff/xml section, but can't piece it together properly.
To clarify, for COUNT(distinct rc.Event) = 2, I would like to see 2 distinct events from the stuff clause. How can I do this?
Use select distinct in the subquery:
select rc.Routage,
count(distinct rc.Event),
stuff((select distinct ', ' + cast(rcA.Event as varchar(max))
from Receiving rcA
where rcA.supplier = 'user' and
rcA.DATETIME > '20170322' and
rc.Routage = rcA.Routage
for xml path('')
), 1, 2, '')
from Receiving rc
where rc.supplier = 'user' and rc.DATETIME > '20170322'
group by rc.Routage;
Notes:
In SQL Server, never use varchar() (or related types) without a length. The default varies by context and you are (potentially) introducing a bug that is really hard to find.
You want the stuff() to remove two characters, not 1, because you have a comma followed by a space.
This formulation assumes that Event does not have XML special characters. It is easy to tweak if that is an issue.
Also, this type of query is usually faster if you eliminate the duplicates in a subquery:
select rc.Routage, rc.numEvents,
stuff((select distinct ', ' + cast(rcA.Event as varchar(max))
from Receiving rcA
where rcA.supplier = 'user' and
rcA.DATETIME > '20170322' and
rc.Routage = rcA.Routage
for xml path(''), type
).value('.', 'varchar(max)'
), 1, 2, ''
)
from (select rc.Routage, count(distinct rc.Event) as numEvents
from Receiving rc
where rc.supplier = 'user' and rc.DATETIME > '20170322'
group by rc.Routage
) rc;
Do the distinct in a subquery, before the XML processing gets anywhere near it:
select rc.Routage
, COUNT(distinct rc.Event)
, STUFF((select ', ' + cast(rcA.Event as varchar)
from (select distinct Event from Receiving a
where supplier = 'user'
and DATETIME > '20170322'
and rc.Routage=a.Routage
) rcA
for xml path(''))
, 1, 1, '')
from Receiving rc
where rc.supplier = 'user'
and rc.DATETIME > '20170322'
group by rc.Routage
order by COUNT(distinct rc.Event)desc
I am using CTE to convert xml to csv so that it can be exported to a file, however if I have an empty xml tag, this currently gets ignored.
Here is my initial solution courtesy of this previous very helpful post:
https://stackoverflow.com/a/23785202/6260721
Here is my sql:
CREATE TABLE EXPORT_TEST
(
DATA varchar(max)
)
INSERT INTO EXPORT_TEST (DATA)
VALUES ('<EXPORT_DATA><ID>ABC123</ID><PRICE_A>5.6</PRICE_A><PRICE_B></PRICE_B><PRICE_C>8.1</PRICE_C></EXPORT_DATA>')
DECLARE #commaSeparatedValues NVARCHAR(MAX)
DECLARE #xml XML = (SELECT TOP 1 CONVERT(xml,DATA) FROM EXPORT_TEST)
;WITH cte AS (
SELECT
rownr = ROW_NUMBER() OVER (ORDER BY #commaSeparatedValues),
Tbl.col.query('.') AS [xml]
FROM #xml.nodes('EXPORT_DATA') Tbl(col)
), cols AS (
SELECT
rownr,
Tbl.Col.value('.', 'nvarchar(max)') AS Value
FROM cte
CROSS APPLY cte.xml.nodes('//text()') Tbl(Col)
)
INSERT INTO EXPORT_TEST(DATA)
SELECT DISTINCT
STUFF((
SELECT ',' + IIF(ISNUMERIC(value) = 1, Value, '''' + Value + '''')
FROM cols SSF WHERE SSF.rownr = S.rownr
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'
), 1, 1, '') as DATA
FROM cols S
SELECT * FROM EXPORT_TEST
At the moment, it is returning:
'ABC123',5.6,8.1
But I don't want it to ignore PRICE_B, I want it to return an empty string:
'ABC123',5.6,,8.1 <--extra comma required where PRICE_B should be
How can I achieve this?
Besides the possibility to shredd the full XML and re-concatenate its values (there is an answer already), you might use FLWOR-XQuery:
DECLARE #xml XML=
'<EXPORT_DATA>
<ID>ABC123</ID>
<PRICE_A>5.6</PRICE_A>
<PRICE_B />
<PRICE_C>8.1</PRICE_C>
</EXPORT_DATA>';
EDIT better to read with a variable $txt instead of ($n/text())[1]
SELECT
STUFF
(
#xml.query('
let $r:=/EXPORT_DATA
for $n in $r/*
let $txt:=($n/text())[1]
return if(empty($txt) or not(empty(number($txt)))) then
concat(",",string($txt))
else concat(",''",string($txt),"''")
').value('.','nvarchar(max)'),1,1,'');
The result
'ABC123' ,5.6 , ,8.1
This code works on a mass of records using XQUERY.
I'm assuming char(10) (Line Feed) does not appear in your data.
I'm assuming the maximum length of the concatenated text is 1000 (I don't want to use varchar(max) for no good reason)
You can change both of these assumptions if you wish
declare #separator char(1) = char(10)
select substring
(
replace
(
cast
(
cast(DATA as xml).query
(
'for $i in //*
where not($i/*)
return concat
(
sql:variable("#separator")
,if(local-name($i) = "ID") then ('''''''') else ('''')
,($i/text())[1]
,if(local-name($i) = "ID") then ('''''''') else ('''')
)'
) as nvarchar(1000)
) ,' ' + #separator ,','
) ,2 ,1000
) as csv
from EXPORT_TEST
INSERT INTO EXPORT_TEST (DATA) VALUES
('<EXPORT_DATA><ID>ABC123</ID><PRICE_A>5.6</PRICE_A><PRICE_B></PRICE_B><PRICE_C>8.1</PRICE_C></EXPORT_DATA>')
,('<EXPORT_DATA><ID>DEF456</ID><PRICE_A>6.7</PRICE_A><PRICE_B>66.77</PRICE_B><PRICE_C>7.2</PRICE_C></EXPORT_DATA>')
,('<EXPORT_DATA><ID>GHI789</ID><PRICE_A></PRICE_A><PRICE_B>88.99</PRICE_B><PRICE_C></PRICE_C></EXPORT_DATA>')
csv
'ABC123',5.6,,8.1
'DEF456',6.7,66.77,7.2
'GHI789',,88.99,
What about this:
;WITH cte AS (
SELECT
rownr = ROW_NUMBER() OVER (ORDER BY #commaSeparatedValues),
Tbl.col.query('.') AS [xml]
FROM #xml.nodes('EXPORT_DATA') Tbl(col)
), cols AS (
SELECT
rownr,
Tbl.Col.value('.', 'nvarchar(max)') AS Value
FROM cte
CROSS APPLY cte.xml.nodes('EXPORT_DATA/child::node()') Tbl(Col)
)
INSERT INTO EXPORT_TEST(DATA)
SELECT DISTINCT
STUFF((
SELECT ',' + IIF(ISNUMERIC(value) = 1 OR LEN(value) = 0, Value, '''' + Value + '''')
FROM cols SSF WHERE SSF.rownr = S.rownr
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'
), 1, 1, '') as DATA
FROM cols S
Using cte.xml.nodes('EXPORT_DATA/child::node()') in the second CTE will give as all nodes:
;WITH cte AS (
SELECT
rownr = ROW_NUMBER() OVER (ORDER BY #commaSeparatedValues),
Tbl.col.query('.') AS [xml]
FROM #xml.nodes('EXPORT_DATA') Tbl(col)
)
SELECT
rownr
,Tbl.Col.query('.')
,Tbl.Col.value('.', 'nvarchar(max)') AS Value
FROM cte
CROSS APPLY cte.xml.nodes('EXPORT_DATA/child::node()') Tbl(Col)
Then, in the concatenation we need to add check for empty string:
IIF(ISNUMERIC(value) = 1 OR LEN(value) = 0, Value, '''' + Value + '''')
I need help.
I write this query
SELECT SUM(fi.etiliquido) FROM fi WHERE fi.fno IN (
SELECT * from divideString(
SELECT TOP 1 REPLACE(CAST( u.nrdoc AS nvarchar),'/',',') FROM u_ups1 as u WHERE 1057 IN (
SELECT * FROM divideString(REPLACE(CAST(u.nrdoc AS nvarchar),'/',','))
)
)
)
but sql server return this error
Msg 156, Level 15, State 1, Line 4 Incorrect syntax near the keyword
'SELECT'. Msg 102, Level 15, State 1, Line 7 Incorrect syntax near
')'.
and I don't know why.
Can you help me?
UPDATE
divideString is a function get a string and returns the numbers in that string
CREATE FUNCTION divideString (#InStr VARCHAR(MAX))
RETURNS #TempTab TABLE
(id int not null)
AS
BEGIN
SET #InStr = REPLACE(#InStr + ',', ',,', ',')
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%,%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #TempTab(id) VALUES (#VALUE)
END
RETURN
END
You need parentheses around subqueries (except for in subqueries), so:
SELECT SUM(fi.etiliquido)
FROM fi
WHERE fi.fno IN (SELECT d.val
FROM divideString( (SELECT TOP 1 REPLACE(CAST( u.nrdoc AS nvarchar(max)), '/', ',')
FROM u_ups1 as u
WHERE 1057 IN (SELECT d.val
FROM divideString(REPLACE(CAST(u.nrdoc AS nvarchar(max)), '/', ',') d(val)
)
)
) d(val)
);
Also, using TOP with no ORDER BY is usually suspicious.
Storing multiple values in a single column is not recommended. However, I don't think you need a table-valued functions for this. LIKE should work:
SELECT SUM(fi.etiliquido)
FROM fi
WHERE EXISTS (SELECT 1
FROM (SELECT TOP 1 u.nrdoc
FROM u_ups1 u
WHERE '/' + u.nrdoc + '/' LIKE '%/1057/%'
) u
WHERE '/' + u.nrdoc + '/' LIKE '%/' + fi.fno + '/%'
);
And what you might want:
And, the logic that you want might be as simple as this:
SELECT SUM(fi.etiliquido)
FROM fi
WHERE EXISTS (SELECT 1
FROM u_ups1 u
WHERE '/' + u.nrdoc + '/' LIKE '%/1057/%' AND
'/' + u.nrdoc + '/' LIKE '%/' + fi.fno + '/%'
);
I have the following select statement that returns exactly what I want:
DECLARE #result varchar(max) = ''
SELECT #result += (result.Fullname + '<br/>')
FROM (SELECT DISTINCT Fullname
FROM Providers
WHERE Status='A') as result
select substring(#result, 0, len(#result) - 4)
The only problem is, I want the output from this query to be displayed as a column entry from a larger select statement.
Eg.
SELECT
Column AS [AColumnName],
SELECT #result += (result.Fullname + '<br/>')
FROM (SELECT DISTINCT Fullname
FROM Providers
WHERE Status='A') as result
select substring(#result, 0, len(#result) - 4) as [LenderList]
FROM
Table
But I am currently getting the error: Incorrect syntax near the keyword 'SELECT'.
The error pointing to line 4
Any ideas?
You need aggregate string concatenation in SQL Server. There are already many answers on the subquery, but to save you the trouble:
SELECT Column AS [AColumnName],
STUFF((SELECT DISTINCT '<br/>' + Fullname
FROM Providers
WHERE Status = 'A'
FOR XML PATH (''), TYPE
).value('.', 'varchar(max)'
), 1, 5, ''
) as result
FROM Table;
The use of the type is important because your string has special XML characters.
Can you simply run it in 2 statements?
SELECT #result += (result.Fullname + '<br/>')
FROM (SELECT DISTINCT Fullname
FROM Providers
WHERE Status='A') as result
SELECT
Column AS [AColumnName],
substring(#result, 0, len(#result) - 4)
FROM Table
Which Database? If you can use for xml, then something like...
select substring(a.innards, 0, len(a.innards) - 4) as [LenderList]
from
(
SELECT innards = STUFF(
(SELECT DISTINCT Fullname + '</br>'
FROM Providers
WHERE [Status] = 'A'
FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)')
, 1
, 0
, '')
) a
This query gives me all the information that I need, however I'm wanting to display it differently if possible. The current result: http://i.imgur.com/BFKGFSx.jpg
DECLARE #MainHospital varchar(50)='HOSPITAL 1';
SELECT MainEmail, chkOutpatient, chkPartB
FROM SurveyPicList
WHERE MainHospital = #MainHospital
GROUP BY MainHospital, MainEmail, chkOutpatient, chkPartB
I'm trying to return 2 different list of MainEmail comma-delimited if they = "on" in chkOutpatient and chkPartB. So only 2 cells of data as a result. 1 header of chkOutpatient with a list of comma dilmeted emails that = "on", and 1 header of chkPartB with the same.
So for chkPartB, something like this?http://i.imgur.com/RFlV24Q.jpg
SELECT DISTINCT ', ' + MainEmail AS chkPartB
FROM SurveyPicList
WHERE MainHospital = #MainHospital
AND chkPartB = 'on'
Please let me know if my question is unclear or if I need to give more info.
WITH Outpatients AS (
SELECT DISTINCT MainEmail
FROM SurveyPicList
WHERE MainHospital = #MainHospital
AND chkOutpatient = 'on'
)
,OutpatientsRawCsv AS (
SELECT (
SELECT ',' + MainEmail
FROM Outpatients
FOR XML PATH('')
) AS Csv
)
,PartBs AS (
SELECT DISTINCT MainEmail
FROM SurveyPicList
WHERE MainHospital = #MainHospital
AND chkPartB = 'on'
)
,PartBRawCsv AS (
SELECT (
SELECT ',' + MainEmail
FROM PartBs
FOR XML PATH('')
) AS Csv
)
SELECT STUFF(OutpatientsRawCsv.Csv, 1, 1, '') AS OutpatientsCsv
,STUFF(PartBRawCsv.Csv, 1, 1, '') AS PartBCsv
FROM OutpatientsRawCsv
CROSS JOIN PartBRawCsv