I need to have a dynamic SQL statement which should do aggregations on the columns which will pass to it as variables. But I got the below error.
The pseudo code is as follow:
DECLARE #sql nvarchar(max)
DECLARE #params nvarchar(max)
SET #sql = N'SELECT #Input1, #Input2, COUNT(ID) FROM Customers GROUP BY #Input1, #Input2'
SET #params = N'#Input1 nvarchar(225), #Input2 nvarchar(255)'
sp_executesql #sql, #params, #Input1 'Name', #Input2 'Age'
And the error is as bellow:
"Each GROUP BY expression must contain at least one column that is not
an outer reference."
I don't really get the cause of this error, so any help is appreciated in advance.
You have a couple of options, sqlcmd allows substitution for things like column names, or you need to build up the query dynamically. Ensure you check the inputs to avoid sql injection.
SET #sql = N'SELECT ' + #Input1 + ', ' + #Input2 + ', COUNT(ID) FROM Customers GROUP BY ' + #Input1 + ', ' + #Input2;
Related
I have a products table and i need to concat my string and my sql statements. Is there any way?
My purpose is that i want to define column names just one time in a string variable and i will use it alot of times. Otherwise my sql statements has alot of column name and it complex my code.
For example, i use this
DECLARE #MyStr NVARCHAR(MAX) = 'ProdId,ProdName'
SELECT TOP 10 #MyStr FROM Products
Result is here
But i need the result as this.
You'll need to use dynamic SQL here. I also suggest you fix your design and don't store delimited data, and ideally use a table type parameter. This would look like the following:
DECLARE #Columns table (ColumnName sysname);
INSERT INTO #Columns (ColumnName)
VALUES(N'Column1'),(N'Column2');
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME(ColumnName),N',') + #CRLF +
N'FROM dbo.Products;'
FROM #Columns;
PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL;
If you don't want to use a table type, you can use STRING_SPLIT:
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME([Value]),N',') + #CRLF +
N'FROM dbo.Products;'
FROM STRING_SPLIT(#Columns,',');
I want to select the store procedure parameter as aliases in select statement in sql
example i have two parameter in store procedure
#programcode int,
#class int
Query where I want use those parameters as alias.
select programcode as #programcode from tbl_name
Why would you want a column alias to be a number?
In any case, you can write this as:
DECLARE #sql nvarchar(MAX);
SET #sql = N'
SELECT programcode AS [' + CAST(#programcode AS VARCHAR(MAX)) + ']
FROM tbl_name
';
EXEC sp_executesql #sql;
Numbers are not really recommended for column aliases, so they need to use escapes.
Try this query.
DECLARE #SqlText nvarchar(MAX);
SET #sqlText = N'SELECT programcode AS ' + CAST(#programcode AS VARCHAR(MAX)) + ' FROM tbl_name'
Exec (#sqlText)
i want have the layout of pivot table with on top period YYYYMM in dynamic table.
show sum of consumption per month show 1 year.
but when i tried put the data (period (201801,201802...)) don't work with PERIOD table on dynamic ?!!
i don't know if im doing something wrong on the report ...can anyone help withit ?
The query without be in dynamic and work but when I tried to change to dynamic I can't make it work.
DECLARE #ColumnNames NVARCHAR(MAX) = ' '
DECLARE #SQL NVARCHAR (MAX) = ' '
SELECT #ColumnNames += QUOTENAME(Period) + ','
FROM [STOKVIS LIVE].[dbo].[SR_CONS_Consumption1year]
SET #ColumnNames = LEFT (#ColumnNames,LEN(#ColumnNames)-1)
SET #SQL =
SELECT [No_] ,[Group],[Lakeview],[Name],[class.],[Stock], [Period]
FROM [STOKVIS LIVE].[dbo].[SR_CONS_Consumption1year]
PIVOT (
SUM ([Qty])
FOR [Period]
IN( ' + #ColumnNames + ')
)
as pivortable
You are executing 2 queries that require dynamic syntax - I've not tested but I think you could try something like this:
--Declare Variables
DECLARE #ColumnNames NVARCHAR(MAX) = NULL
DECLARE #SQL NVARCHAR(MAX)
-- First dynamic query
SET #SQL = N'
SELECT #ColumnNames += QUOTENAME(Period) + '',''
FROM [STOKVIS LIVE].[dbo].[SR_CONS_Consumption1year] ;';
--Execute dynamic query
EXEC sp_executesql #sql, N'#ColumnNames NVARCHAR(MAX)', #ColumnNames;
SET #ColumnNames = LEFT (#ColumnNames,LEN(#ColumnNames)-1)
--second dynamic query
SET #SQL = N'
SELECT [No_] ,[Group],[Lakeview],[Name],[class.],[Stock], [Period]
FROM [STOKVIS LIVE].[dbo].[SR_CONS_Consumption1year]
PIVOT (
SUM ([Qty])
FOR [Period]
IN( ' + #ColumnNames + ')
)
AS PivotTable ;';
EXEC sp_executesql #sql, N'#ColumnNames NVARCHAR(MAX) OUT', #ColumnNames OUT;
SELECT #TransType
EDIT
Added OUT in the past EXEC to identify they are output variables so you can use SELECT #TransType to get the result
I was wondering if there is a way to select a column by using a SQL variable. Eg. Table is -
ID, Name, Address
DECLARE #Column varchar(25)
SET #Column = 'Name' -- This can be another column also
SELECT #Column
FROM MyTable
This shows me 'Name' as many times as there are rows in my table.
Is it even possible to do what I want ?
thanks.
Can do this with dynamic SQL:
DECLARE #Column varchar(25)
,#sql VARCHAR(MAX)
SET #Column = 'Name' -- This can be another column also
SET #sql = 'SELECT '+#Column+'
FROM MyTable
'
EXEC (#sql)
You can test your dynamic sql queries by changing EXEC to PRINT to make sure each of the resulting queries is what you'd expect.
You can use dynamic SQL for that:
DECLARE #Column nvarchar(25)
SET #Column = 'Name' -- This can be another column also
DECLARE #sql nvarchar(max) = N'SELECT ' + #Column + N' FROM MyTable'
exec(#sql)
Sql is currently interpreting your variable as a string.
From a previous answer on stack overflow:
DECLARE #Column varchar(25)
SET #Column = 'Name' -- This can be another column also
SET #sqlText = N'SELECT ' + #Column + ' FROM MyTable'
EXEC (#sqlText)
I have a SQL query string that is like this:
DECLARE #sql varchar(max)
SET #sql = ' INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, ' +
'''' + #name + ''' as CompanyName ' +
' FROM #tempTable2 tt2'
The query runs fine except for two names that happen to contain a single quote (ex: Pete's Corner). When either one of these names becomes part of the query it breaks the query string. I thought the easiest thing to do would be to replace the single quote like this replace(#name,'''','') but it doesn't work because I'm already in a string and so its affecting the rest of the statement. Altering the table itself is not an option unfortunately.
How can I replace or remove these single quotes?
Addition: I apologize, I did not include the part where #name is actually being populated from another database table by a join so setting the value of #name before the string is created I think would be difficult for me.
Why do you need to do this at all? You should be passing strong parameters to sp_executesql instead of munging all of your parameters into a single string and using EXEC(). More info on that here.
DECLARE #sql NVARCHAR(MAX), #name NVARCHAR(32);
SET #name = 'Pete''s Corner';
SET #sql = 'INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, #name as CompanyName ' +
' FROM #tempTable2 tt2';
EXEC sp_executesql #sql, N'#name NVARCHAR(32)', #name;
I presume the #name parameter actually gets populated from elsewhere, and if using proper parameterization you shouldn't have to deal with escaping the '.
Now I'm not quite sure what #tempTable1 is supposed to represent, or if you can access #tempTable2 from this scope, but whenever you find yourself running a replace that requires '''' or '''''' (or both), you should ask yourself if maybe there's a better way.
I think this should do it:
DECLARE #sql varchar(max)
SET #sql = ' INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, ' + ''''+
replace( #name ,'''','''''')+''''+' as CompanyName
FROM #tempTable2 tt2'
You can use sp_executesql system procedure. sp_executesql will allow you to call dynamic SQL with #name parameter instead of embedding it into the SQL.
DECLARE #sql nvarchar(max),
#name varchar(50)
SET #name = 'qwe'''
SET #sql = 'INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, ' +
'#name as CompanyName ' +
'FROM #tempTable2 tt2'
--PRINT #sql
EXEC sp_executesql #sql, N'#name varchar(50)', #name