Pivot Table "Incorrect Syntax" - sql

I'm trying to group my sql table together, but I am receiving an "incorrect syntax"
Declare #pet varchar(max)
SET #pet = (select petsName from pets);
select * from pets
AS basedata
Pivot (
count(PetID)
for petsName in (' + #pet+ ') <-- error here
)
as pivottable
Why am I receiving an incorrect syntax near #pet?
Thanks

You need to use dynamic sql for this
DECLARE #pet VARCHAR(max)
SET #pet = (SELECT ',' + Quotename(petsName) -- Quotename is used to escape illegal characters
FROM pets
FOR xml path('')); -- to concatenate the records
SET #pet = Stuff(#pet, 1, 1, '') -- to remove the leading comma
DECLARE #sql NVARCHAR(8000) = ''
SET #sql = '
select * from pets AS basedata
Pivot ( count(PetID)
for petsName in (' + #pet + ') ) as pivottable'
exec sp_executesql #sql -- to execute the dynamically framed string
Another mistake in your query is, you are trying to assign petsName to #pet variable.
SET #pet = (select petsName from pets);
But a variable can store only one record. So you need to concatenate the records into one single record separated by comma. Then the variable can be used in pivot list
SET #pet = (SELECT ',' + Quotename(petsName)
FROM pets
FOR xml path(''));

Related

Passing parameter to stored procedure using dynamic SQL into pivot data

I am trying to pass a parameter into Stored procedure to filter data in my select statement but when i use the parameter it gives error Message: Invalid column name 'SessionId2075'. when I use static value in the where clause the procedure works fine. Can you please give me fix the issue. I checked all the previous answers and could not find the working solution.
Alter PROCEDURE [dbo].GetPivotFeeReport
(
#SessionId varchar(50)
)
as
begin
DECLARE #SQL as VARCHAR(MAX)
DECLARE #Columns as VARCHAR(MAX)
SET NOCOUNT ON;
SELECT #Columns =
COALESCE(#Columns + ', ','') + QUOTENAME(GroupHeaderValue)
FROM
(SELECT DISTINCT mgh.GroupHeaderValue
FROM StudentFeeDetail sf
INNER JOIN MasterGroupHeaderValue mgh
ON mgh.GroupHeaderValueId = sf.FeeForId
) AS B
ORDER BY B.GroupHeaderValue
SET #SQL = 'SELECT ClassName,' + #Columns + ',TOTAL
FROM
(
SELECT
distinct mc.className,
sf.FinalAmount,
mgh.GroupHeaderValue,
Sum (isnull(sf.FinalAmount,0)) over (partition by ClassName) AS TOTAL
--0 AS TOTAL
FROM StudentFeeDetail sf
INNER JOIN StudentAdmission sa
ON sa.AdmissionId = sf.AdmissionId
INNER JOIN MasterClass mc
ON mc.ClassId = sa.ClassId
INNER JOIN MasterGroupHeaderValue mgh
ON mgh.GroupHeaderValueId = sf.FeeForId
WHERE sa.SessionId = (' + #SessionId + ') -- this is where I am trying to use the parameter when used static value like this ''SessionId2075'' the procedure works fine
and sf.FeeAmt >0
GROUP BY className, FinalAmount, GroupHeaderValue
) as PivotData
PIVOT
(
sum(FinalAmount)
FOR GroupHeaderValue IN (' + #Columns + ')
) AS PivotResult
ORDER BY (ClassName)
'
EXEC ( #sql)
end

Creating "Not Exists"/Insert Into Statements - Stumped by nothing (NULL)

I need a script that generate insert statements but with check for if the data doesn't already exist, this because it should be periodically run on parallell systems where different dtata will be added to the systems but we want them tables to be in sync. I have the basic ides and borrowed parts of code but get a syntax error i have trouble solving.
I'm basing my code on the code Param Yadav showed at Converting Select results into Insert script - SQL Server but I need to check for data already in the table. (I need to add more "bells & whistles later, but take this step-by-step)
My own main addition is the #NOT_EXISTS part which should be in the WHERE clause of the NOT EXISTS check. If I replace that with a plain WHERE 0=1 I get no syntax error so it indicates the error is in my #NOT_EXISTS string.
Edit: Yesterday I thought I had an answer to my own question but when running on "real data" I saw that some lines are too long for QUOTENAME, I have to fix those quotation marks "manually" (concats in script) instead...
SET NOCOUNT ON
DECLARE #CSV_COLUMN VARCHAR(MAX),
#QUOTED_DATA VARCHAR(MAX),
#NOT_EXISTS VARCHAR(MAX),
#SQL_KOD VARCHAR(MAX),
#TABLE_NAME VARCHAR(MAX),
#FILTER_CONDITION VARCHAR(MAX)='',
#FIRST_COL INT,
#LAST_COL INT
/* INPUT DATA */
SELECT #TABLE_NAME = 'WorkflowError'
SELECT #FIRST_COL = 2
SELECT #LAST_COL = 4
/* */
SELECT #CSV_COLUMN=STUFF
(
(
SELECT ',['+ NAME +']' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
--SELECT #CSV_COLUMN
SELECT #QUOTED_DATA=STUFF
(
(
SELECT ' ISNULL(QUOTENAME('+NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+')+'','''+'+' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=SUBSTRING(#QUOTED_DATA,1,LEN(#QUOTED_DATA)-5)
SELECT #QUOTED_DATA
SELECT #NOT_EXISTS=STUFF
(
(
SELECT ' ['+ COLUMN_NAME +']=', 'ISNULL(QUOTENAME('+COLUMN_NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+') AND '
FROM information_schema.columns
WHERE table_name = #TABLE_NAME AND
ordinal_position BETWEEN #FIRST_COL AND #LAST_COL
FOR XML PATH('')
),1,1,''
)
SELECT #NOT_EXISTS=SUBSTRING(#NOT_EXISTS,1,LEN(#NOT_EXISTS)-4)
SELECT #NOT_EXISTS
--SELECT #NOT_EXISTS=' 0=1 '
SELECT #SQL_KOD='SELECT ''
IF NOT EXISTS(SELECT 1
FROM ' + #TABLE_NAME + ' WHERE ' + #NOT_EXISTS + ')
BEGIN
INSERT INTO '+#TABLE_NAME+'('+#CSV_COLUMN+')
VALUES('''+'+'+#QUOTED_DATA+'+'+''')
END
GO '''+' Insert_Scripts
FROM '+#TABLE_NAME + #FILTER_CONDITION
SELECT #SQL_KOD
EXECUTE (#SQL_KOD)
GO
[stackoverflow won't let me post code unless it's formatted, but then the strings below won't be as they are created in the script...]
When I do SELECT #NOT_EXISTS=' 0=1 ' I get an INSERT line for each row in my table:
IF NOT EXISTS(SELECT 1 FROM WorkflowError WHERE 0=1 )
BEGIN
INSERT INTO WorkflowError([TargetSystem],[ErrorCode],[ErrorText],[RetryMaxCount],[RetryStrategyName],[ErrorDescription])
VALUES('EttLiv','800','Value cannot be null. Parameter name: source','0',NULL,'Value cannot be null. Parameter name: source')
END
GO
With my #NOT_EXISTS code the #SQL_KOD string becomes this:
SELECT 'IF NOT EXISTS(SELECT 1 FROM WorkflowError
WHERE [TargetSystem]=ISNULL(QUOTENAME(TargetSystem,''''),'NULL'))
BEGIN
INSERT INTO WorkflowError([TargetSystem],[ErrorCode],[ErrorText],[RetryMaxCount],[RetryStrategyName],[ErrorDescription])
VALUES('+ISNULL(QUOTENAME(TargetSystem,''''),'NULL')+','
+ ISNULL(QUOTENAME(ErrorCode,''''),'NULL')+','
+ ISNULL(QUOTENAME(ErrorText,''''),'NULL')+','
+ ISNULL(QUOTENAME(RetryMaxCount,''''),'NULL')+','
+ ISNULL(QUOTENAME(RetryStrategyName,''''),'NULL')+','
+ ISNULL(QUOTENAME(ErrorDescription,''''),'NULL')+')
END
GO ' Insert_Scripts FROM WorkflowError
However, trying to execute that #SQL_KOD line just gives:
Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'NULL'.
...and I can't find out where I have done wrong, if it's in my thinking or if it's just a misplaced quotation mark...
Where do you expect #SQL_KOD to get its values from? Because if you are retrieving your values for TargetSystem / ErrorCode / ... / ErrorDescription from somewhere outside of your insert statement, I would expect a "from" statement. If you want to input variables, you are missing both the definition of the variables and the #-sign in front of the variable name.
As far as keeping quotes happy: try writing your code with QUOTED_IDENTIFIER OFF - you can create the entire #SQL_KOD variable by writing between double quotes ("), and single quotes would behave like normal quotation marks.
A very basic re-write of your code could be something as follows:
SET QUOTED_IDENTIFIER OFF
DECLARE #SQL_KOD VARCHAR(MAX)
SET #SQL_KOD =
"DECLARE #WorkFlowError TABLE ([TargetSystem] NVARCHAR(200),[ErrorCode] NVARCHAR(200))
IF NOT EXISTS ( SELECT 1 FROM #WorkFlowError )
BEGIN
INSERT INTO #WorkFlowError ([TargetSystem],[ErrorCode])
SELECT ISNULL(QUOTENAME([TargetSystem],''''),'NULL')
, ISNULL(QUOTENAME([ErrorCode],''''),'NULL')
FROM (
SELECT [TargetSystem]='Foo'
, [ErrorCode]='Bar'
) src
END";
I originally used QUOTENAME as in the Param Yadav script I borrowed from but that function can't handle long strings. It doesn't complain, just returns NULL if the string is too long. Now the script is less readable (long lines of quotation marks) but now works.
SET NOCOUNT ON
DECLARE #CSV_COLUMN VARCHAR(MAX),
#QUOTED_DATA VARCHAR(MAX),
#NOT_EXISTS VARCHAR(MAX),
#SQL_KOD VARCHAR(MAX),
#TABLE_NAME VARCHAR(MAX),
#FILTER_CONDITION VARCHAR(MAX),
#FIRST_COL INT,
#LAST_COL INT
/* INPUT DATA */
SELECT #TABLE_NAME = 'WorkflowError'
SELECT #FIRST_COL = 2
SELECT #LAST_COL = 4
SELECT #FILTER_CONDITION = ''
/* */
SELECT #CSV_COLUMN=STUFF
(
(
SELECT ',['+ NAME +']' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=STUFF
(
(
SELECT ' ISNULL('''''''' + REPLACE('+NAME+','''''''','''''''''''') + '''''''','''+'NULL'''+''+')+'',''+'
FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=SUBSTRING(#QUOTED_DATA,1,LEN(#QUOTED_DATA)-5)
SELECT #NOT_EXISTS=STUFF
(
(
SELECT ' ['+ COLUMN_NAME +']='' + ', 'ISNULL('''''''' + REPLACE('+COLUMN_NAME+','''''''','''''''''''') + '''''''','''+'NULL'''+''+')+'' AND '
FROM information_schema.columns
WHERE table_name = #TABLE_NAME AND
ordinal_position BETWEEN #FIRST_COL AND #LAST_COL
FOR XML PATH('')
),1,1,''
)
SELECT #NOT_EXISTS=SUBSTRING(#NOT_EXISTS,1,LEN(#NOT_EXISTS)-6)
SELECT #SQL_KOD='SELECT ''IF NOT EXISTS(SELECT 1 FROM ' + #TABLE_NAME + ' WHERE ' + #NOT_EXISTS + ' + ' + ''') BEGIN INSERT INTO '+#TABLE_NAME+'('+#CSV_COLUMN+')VALUES('''+'+'+#QUOTED_DATA+'+'+''') END '''+' Insert_Scripts FROM ' + #TABLE_NAME + ' ' + #FILTER_CONDITION
EXECUTE (#SQL_KOD)
SET NOCOUNT OFF

How to create temp table with dynamic SQL query result

I have this stored procedure:
Declare #MarketID AS NVARCHAR(MAX) = '1.136529848';
Declare #UserID AS NVARCHAR(MAX) = '6a309d84-d1c6-434d-b9df-4f96a74da912';
DECLARE #colsSelect AS NVARCHAR(MAX);
DECLARE #colsTemp AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
SELECT
#colsSelect = STUFF((SELECT distinct ',' +
'''''' + ' as ' + QUOTENAME(name)
FROM RunnersInfoes AS t
WHERE marketID = #MarketID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '');
PRINT #colsSelect
SET #query= ';WITH cte AS
(
SELECT
id, ParentId, 0 AS Level, Share, AccountTypeName, FirstName
FROM
dbo.View_UserProfile
WHERE
View_UserProfile.id = ' + '''' + #UserID + '''' +'
UNION ALL
SELECT
t.id, t.ParentId, Level + 1 AS Level, t.Share, t.AccountTypeName, t.FirstName
FROM
View_UserProfile t
INNER JOIN
cte ON t.ParentId = cte.id
)
SELECT
ID, AccountTypeName AS Type, FirstName AS Name, ' + #colsSelect + '
FROM cte AS t'
EXECUTE (#query)
and it's generating this result:
I want to create temp table or variable type table for following result , remember the column of this result are dynamically rendered. Sometimes result returns more columns and sometimes with less but first 3 columns remain the same for every result. So kindly help for creating dynamic table inside the stored procedure.
You can do:
SELECT ID
, AccountTypeName AS Type
, FirstName AS Name
, ' + #colsSelect + '
INTO ##TEMPTABLE
FROM cte AS t
Since you execute this dynamically, you cannot use #TEMPTABLE because a local temp table will only exist in the scope of the query that defines it. Using ## creates a global temp table which will be accessible outside the scope of the dynamic query.
Please use the SELECT - INTO clause for your use case as given below
SELECT * INTO #temptable FROM cte
To create a temp table that is filled by a dynamic query, use global temp tables like this example.
For the select ... into ... statement to work, you need to make sure every column from the select has a name.
declare #query varchar(1000) = 'select 1 as ID, ''test'' as Column_1 into ##mytable'
exec (#Query)
select * from ##mytable
drop table ##mytable
Do not forget to drop the temp table when your done.

Return SELECT query result as a CSV string

I have the following Sql Server 2016 SELECT statement that returns only 1 row:
SELECT TOP 1 * FROM tempdb.dbo.IMTD
How can I concatenate the values as a comma delimited string? NOTE: the column names of this temporary table are unknown as they can variate.
Thank you.
Something like this perhaps:
-- Sample data
DECLARE #someTable TABLE (SomeID int identity, SomeTxt varchar(100));
INSERT #someTable VALUES ('row1'),('row2'),('row3');
-- Solution
SELECT ConcatinatedString =
STUFF
((
SELECT ','+SomeTxt
FROM #someTable
FOR XML PATH(''), TYPE
).value('.','varchar(100)'),1,1,'');
You can use Dynamic query as below:
DECLARE #COLS VARCHAR(MAX) = ''
SELECT #COLS = #COLS + ',' + COLUMN_NAME
FROM tempdb.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME LIKE '#table[_]%' -- Dynamic Table (here, Temporary table)
DECLARE #COLNAMES VARCHAR(MAX) = REPLACE(STUFF(#COLS, 1, 1, ''), ',', '+ '','' +')
Declare #cmd varchar(max) = 'Select ' + #COLNAMES + ' as CSVCol from #table'
-- will generate
-- Select Column1+ ',' +Column2+ ',' +Column3 as CSVCol from #table
EXEC (#cmd)
Another solution you can try is this.
SELECT LTRIM(RTRIM(<ColumnName1>)) + ',',
LTRIM(RTRIM(<ColumnName2>)) + ',',
...
LTRIM(RTRIM(<ColumnNamen>)) + ','
FROM tempdb.dbo.IMTD
If you only want one row keep that top 1 In there like
SELECT TOP 1
LTRIM(RTRIM(<ColumnName1>)) + ',',
LTRIM(RTRIM(<ColumnName2>)) + ',',
...
LTRIM(RTRIM(<ColumnNamen>)) + ','
FROM tempdb.dbo.IMTD
The LTRIM and RTRIM will remove any white space and this should allow you to copy and paste the result set anywhere you may need it. You will need to do this for each columnname.
You can use the query below to get the column names from your temp table.
DECLARE #ColumnNames NVARCHAR(MAX)
SELECT
#ColumnNames= COALESCE(#ColumnNames +',','')+COLUMN_NAME
FROM
TempDB.INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = '#TempTableName'

Error with Dynamic SQL statement cutting off with exec command

I am attempting to pivot a column with 400 or so unique values with the following code:
Declare #t VARCHAR(10)
Declare #A VARCHAR(1000)
Declare #B VARCHAR(1000)
set #A='SELECT Name, IRIS_ID__c'
SET #B='('
SELECT #A=#A+',['+Question_Concept_With_ImpactArea__c+'] as ['+Question_Concept_With_ImpactArea__c+']',#B=#B+'['+Question_Concept_With_ImpactArea__c+']'
FROM (SELECT DISTINCT Question_Concept_With_ImpactArea__c
FROM Company_Number_Response) cur
-- removing last ',' from both variables
SET #B=SUBSTRING(#B,1,LEN(#B)-1)
SET #A=#A+ + '
FROM
(SELECT NAME, IRIS_ID__c, Selected, Question_Concept_With_ImpactArea__c
FROM Company_Number_Response) s PIVOT (max(Unified_Response__c)
FOR Question_Concept_With_ImpactArea__c IN ' +#B+')) p ORDER BY [IRIS_ID__c];'
exec(#A);
Running this code throws an error that "Unclosed quotation mark after the character string 'CM_PcCOGSSup'
Incorrect Syntax near 'CM_PcCOGSSup'
When I change the last command from exec to print I can see that many of the values are being read, but the statement simply cuts off at the value in the above error. I checked the data and do not see any characters that would be causing this. Additionally, I thought the result might be too long and changed the max number for results to text to 8192.
Any help would be greatly appreciated.
Assuming you're using SQL Server 2005 or up, change your variable declarations to varchar(max). It's cutting off because you've only supplied varchar(1000), and string concatenation does not automatically lengthen char data types--they get truncated.
In SQL 2000 you can only use varchar(8000). If you need longer than that you will have to get creative--a pretty difficult task.
You also have SET #A=#A+ + '. If that's working, it's a surprise to me, but in any case there should only be one + there.
And, you should not just put square brackets around columns to make them a valid sysname data type. You should use the QuoteName function:
SELECT #A = #A + ',' + QuoteName(Question_Concept_With_ImpactArea__c) ...
Try this one -
DECLARE #Columns VARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
SELECT #Columns = STUFF((
SELECT DISTINCT ', ['+ Question_Concept_With_ImpactArea__c + ']'
FROM dbo.Company_Number_Response
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
SELECT #SQL = 'SELECT Name, IRIS_ID__c, ' + #Columns + '
FROM
(
SELECT NAME, IRIS_ID__c, Selected, Question_Concept_With_ImpactArea__c
FROM Company_Number_Response
) s
PIVOT (
max(Unified_Response__c)
FOR Question_Concept_With_ImpactArea__c IN (' + #Columns + ')
) p
ORDER BY [IRIS_ID__c];'
EXEC sys.sp_executesql #SQL