Surrounding query with parenthesis cause error For XML - sql-server

When trying to wrap query for further processing I get an error by just putting parenthesis around the query. See query below, if I simply remove the wrapping parenthesis, the query works. But when I use the parenthesis I get this error:
Incorrect syntax near the keyword 'for'
(
select '; ' + [NAME]
from (select a.[NAME] as 'NAME'
from [MS].[dbo].[A_POSITIONS] a
where a.ID = 208418
except
select top 1 b.[NAME]
from [MS].[dbo].[A_POSITIONS] b
where b.ID = 208418) as c
for XML PATH(''),TYPE
)
Anyone have an idea on why this is happening?
Thanks!

Adding the parenthesis alone around your query leads to an error, but if you type a SELECT before the opening parenthesis the code will run, meaning that you can use it for further processing:
if OBJECT_ID('A_POSITIONS') is not null
drop table [dbo].[A_POSITIONS]
create table [dbo].[A_POSITIONS]([ID] int,[Name] varchar(100))
insert into [dbo].[A_POSITIONS] values
(208418, 'one'),(208418, 'two'),(208418, 'three'),(208418, 'four'),(208418, 'five')
select
(
select '; ' + [NAME]
from (select a.[NAME] as 'NAME'
from [MS].[dbo].[A_POSITIONS] a
where a.ID = 208418
except
select top 1 b.[NAME]
from [MS].[dbo].[A_POSITIONS] b
where b.ID = 208418) as c
for XML PATH(''),TYPE
)
One last consideration: TOP keyword without an ORDER BY clause is non-deterministic.
From Microsoft Docs (more info here):
When TOP is used in conjunction with the ORDER BY clause, the result set is limited to the first N number of ordered rows; otherwise, it returns the first N number of rows in an undefined order
So you should really consider adding an ORDER BY to the second part of your query:
select '; ' + [NAME]
from (select a.[NAME] as 'NAME'
from [MS].[dbo].[A_POSITIONS] a
where a.ID = 208418
except
select top 1 b.[NAME]
from [MS].[dbo].[A_POSITIONS] b
where b.ID = 208418
--Add an ORDER BY clause here
) as c
for XML PATH(''),TYPE

Related

csv from subquery in IN() causes conversion error

CROSS APPLY (
SELECT
ISNULL(
(
SELECT
SUM (R.CALORIE)
FROM
TA_RECIPE AS R
WHERE
R.NO_RECIPE IN ([mp].recipe_ids)
OR R.NO_RECIPE IN ([tags2].recipe_ids)
),
0
) AS caloriePerPortion
) AS [CAL]
The problem is in the part
R.NO_RECIPE IN ([mp].recipe_ids)
OR R.NO_RECIPE IN ([tags2].recipe_ids)
The recipe_ids contain comma seperated lists
when there's only one id in the recipe_ids it works fine but if there is actually a list in recipe_ids sql server interprets this as a varchar instead of a list of integers
wrapping them in STRING_SPLIT causes the query to become very slow (adds seconds to the execution time)
wrapping them in STRING_SPLIT causes the query to become very slow
But that's the only way it can work.
select *
from t
where c in ('1,2,3,4,5')
just doesn't do what you want.
the data isn't stored as csv but was retrieved like that throug cross apply with for xml path
I changed it to
SELECT DISTINCT
MM.MAP_ID AS mapId,
MM.MENU_ID AS menuId,
stuff((select ',' + CAST(RECIPES.recipe_ids AS VARCHAR(MAX)) for xml path('')), 1, 1, '') AS planningRecipe_ids
FROM MM
LEFT JOIN MP ON MM.MENU_ID = MP.MENU_ID
LEFT JOIN RECIPES ON RECIPES.PLANNING_MENU_ID = MP.PLANNING_MENU_ID
but then the for xml path doesn't work

Exec into temp table without columns as they are dynamic

I'm working on pivot functionality, where the pivot columns comes dynamically. All the pivot columns I needs to count and display separate column in pivot select statement itself.
SELECT CurriculumSegment,attendancedate,section,Class,count(*) as
TotalWorkingDays into #NewTempWithTotalDaysCount
FROM #temp1 group by CurriculumSegment,attendancedate,Section,Class
order by CurriculumSegment, attendancedate,Class,Section
SELECT CurriculumSegment,attendancedate,section,Class,count(*) as
CountOfPresentDays into #NewTempWithTotalPresentDaysCount
FROM #temp1 where attendance='P' group by
CurriculumSegment,attendancedate,Section,Class order by CurriculumSegment,
attendancedate,Class,Section
select a.AttendanceDate,a.Class,a.CurriculumSegment,
a.Section,a.TotalWorkingDays,b.CountOfPresentDays,(a.TotalWorkingDays -
b.CountOfPresentDays) as TotalAbsentDays, (b.CountOfPresentDays *
100)/a.TotalWorkingDays as PercentOfPresentDays
into #TempWithTotalDaysCount
from #NewTempWithTotalDaysCount a left outer join
#NewTempWithTotalPresentDaysCount b
on a.AttendanceDate =b.AttendanceDate and a.CurriculumSegment =
b.CurriculumSegment and a.Section= b.Section and a.Class = b.Class
-- Query 1
select sum(TotalWorkingDays) as TotalCount,sum(TotalAbsentDays) as
AbsentCount,sum(CountOfPresentDays) as
PresentCount,curriculumsegment,section,class
from #TempWithTotalDaysCount group by class,curriculumsegment,section
SET #query = 'SELECT [CurriculumSegment],Class,section,'+#cols+'
FROM (
SELECT [CurriculumSegment],
Class,section,PercentOfPresentDays,AttendanceDate FROM
#TempWithTotalDaysCount) AS up
PIVOT (MAX(PercentOfPresentDays) FOR AttendanceDate IN ('+#cols+')) AS pvt'
-- Query 2
EXEC (#query)
From the query 1 and query 2 results, I needs to do join and get the TotalCount, AbsentCount, PresentCount
in the result of query 2.
Is it possible to put "EXEC(#query)" in temp table ?
I tried but I'm getting invalid object. Because I cant give the column names as they come dynamically form pivot.
So,is there any other approach ?
Thank you.
Find out my result in below image:

Invalid object name in a XML Path / Stuff combination

I am trying to get some values from different rows into a single column, and I keep getting this error :
Invalid object name 't'
The query is rather big and complicated so I narrowed it down to a simple part that still gives me the error.
select
IDs = stuff( ( select ',' + convert(varchar, t2.ChassisID)
from t as t2
where t2.ChassisID = 42 --t.ChassisID
for XML path('')
)
, 1, 1, ''
)
from ( select ch.ChassisID, p.GPS
from tblChassis ch
inner join tblPlace p on ch.BestemmingID = p.PlaceID
) t
group by t.Gps
I tried changing the where clause to a fixed number (42) instead of t.ChassidID and still get the error, so there is only one place left that could cause the error I assume, but I cant see why.
I probably am missing something simple but I just cannot see it.
What is wrong with this query ?
I am using Sql Server 2014
Try declaring your filtered table in a CTE, then referencing this CTE both times.
;WITH FilteredChassis AS
(
select
ch.ChassisID,
p.GPS
from
tblChassis ch
inner join tblPlace p on ch.BestemmingID = p.PlaceID
)
select
t.Gps,
IDs = stuff( ( select ',' + convert(varchar, t2.ChassisID)
from FilteredChassis as t2
where t2.Gps = t.Gps
for XML path('')
)
, 1, 1, ''
)
from
FilteredChassis AS t
group by
t.Gps
I've made the link through gps, I believe that's what you need.

Searching stored procedure and views but ignoring comments

I have a query as
select
definition
from
sys.objects so
join
sys.sql_modules ssmsp on so.[object_id] = ssmsp.[object_id]
where
so.type in ('v', 'p')
where
definition like '%exec%'
While populating records, gets populated from comments also. How can I avoid getting filtered from comments?
Is there any solution?
Thanks
I think this is going to be nearly impossible to achieve in a single query.
Bear in mind that [definition] has no formatting, no line breaks, etc. the code is a single line (copy one and paste it into the editor).
If a comment starts with -- then where does it end? you have no way of knowing.
It is a little easier with /* because you can find the corresponding */ but there is still the added complication of multiple occurrences of the search string.
You might have a little more luck using PATINDEX and specifying a case-sensitive version of your collation (if you have a case insensitive database) and for example you know you only want occurrences of EXEC and not "execute" e.g. WHERE patindex('%EXEC%',defintion COLLATE SQL_Latin1_General_CP1_CS_AS) > 0
First for a fast varchar(max) string "splitter". Below is a hacked version of Jeff Moden's delimitedSplit8K.
IF OBJECT_ID('dbo.DelimitedSplit2B','IF') IS NOT NULL DROP FUNCTION dbo.DelimitedSplit2B;
GO
CREATE FUNCTION dbo.DelimitedSplit2B
(
#pString varchar(max),
#pDelimiter char(1)
)
RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH L1(N) AS
(
SELECT N
FROM (VALUES
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(N)
), --216 values
cteTally(N) AS
(
SELECT 0 UNION ALL
SELECT TOP (DATALENGTH(ISNULL(#pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM L1 a CROSS JOIN L1 b CROSS JOIN L1 c
--2,176,782,336 rows: enough to handle 2,147,483,647 characters (the varchar(max) limit)
),
cteStart(N1) AS
(
SELECT t.N+1
FROM cteTally t
WHERE (SUBSTRING(#pString,t.N,1) = #pDelimiter OR t.N = 0)
)
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
Item = SUBSTRING(#pString,s.N1,ISNULL(NULLIF((LEAD(s.N1,1,1)
OVER (ORDER BY s.N1) - 1),0)-s.N1,DATALENGTH(ISNULL(#pString,1))))
FROM cteStart s;
Next for the function to search your DDL
create function dbo.SearchObjectDDLFor (#searchstring varchar(100), #maxLen int)
returns table as return
select objectName, lineNumber, lineText
from
(
select
objectName = ss.[name]+'.'+so.[name],
lineNumber = itemnumber,
lineText = substring(t.item, 1, isnull(nullif(charindex('--', t.item),0)-1, 8000)),
isLongComment =
sum
( -- this will assign a 1 for everything
case when t.item like '/*%' then 1
when t.item like '*/%'then -1
else 0 end
) over (partition by so.[name] order by itemnumber)
from sys.objects so
join sys.sql_modules ssmsp on so.[object_id] = ssmsp.[object_id]
join sys.schemas ss on so.schema_id = ss.schema_id
cross apply dbo.delimitedSplit2B(definition, char(10))
cross apply (values (rtrim(ltrim(replace(item,char(13),''))))) t(item)
where so.type in ('v', 'p')
and len(definition) < isnull(#maxLen,100000) -- character limit is #maxLen (100K default)
) splitLines
where isLongComment = 0 and lineText not like '--%' and lineText <> '*/'
and lineText like '%'+#searchstring+'%';
This function:
Accepts an input string to search for (#searchstring)
Splits your objects into lines
Returns only the portions of the line not part of a comment
filters the lines created in step3 for ones that contain #searchstring and returns the ObjectName (.), Line number and Text.
Caveats:
I just threw this together quick so forgive any errors
A t-sql splitter that accepts [n]varchar(max) will be slow. A CLR splitter would likely be faster but we're not talking about millions of rows. That said, you can speed it up by filtering the number of lines with #maxLen. #maxlen says "ignore and objects with more that #maxLen number of lines." When null it will search objects up to 100K lines long (but this can be adjusted).
This function address comments scenarios where comments look have "--" any where in the string: and scenarios where the comment is nested between "/" and "\ on separate lines.
a few scenarios which require more coding to suppress the comments include:
.
select col1, /* skipping col2 for now */ col3, col4
and
/*********
comments here
*********/
Examples:
select * from dbo.SearchObjectDDLFor('nocount', NULL);
select * from dbo.SearchObjectDDLFor('nocount', 2000);
Results will look something like :

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.

Resources