i have to change column name dynamically in loop in sql, using concat to add string and dynamic column name and getting error-'The definition for column 'CONCAT' must include a data type.'
this is my code-
SELECT #SOURCENAME='['+SOURCE_NAME+']' FROM #temptable2 WHERE [id] = #StartRow;
SET #SQL='ALTER TABLE #TmpWcompData ADD '+#SOURCENAME+' float'
SET #SQL1='ALTER TABLE #TmpWcompData ADD concat(mae,'+#SOURCENAME+') float'
EXECUTE SP_EXECUTESQL #SQL,#SQL1;
CONCAT can’t be used in ALTER TABLE.
You can fix it as the following:
SET #SQL1 = 'UPDATE #TmpWcompData SET ' + #SOURCENAME + ' = CONCAT(mae, ' + #SOURCENAME + ')';
Related
Suppose I want to select a constant value in an sql query, I could do something like this :
select name,age,'tick' from tableA
I want to dynamically generating an sql query using stored procedures. For example :
SELECT #SQL = 'SELECT CID,DOB, NAME, '+#Scname+' from ' + #TableName
Where #TableName, #Scname are dynamically generated variables in a while loop. Here #Scname is interpreted as a column name instead of a constant string when executing query on #TableName. I have tried using escape characters as follows :
SELECT #SQL = 'SELECT CID,DOB, NAME, \"'+#Scname+'\" from ' + #TableName
But it returns a floating point value full of zeros instead of the string contained in #Scname.
I think following should work
SET #SQL = 'SELECT CID,DOB, NAME,'+''''+#Scname+''''+' from '+ #TableName
Try
SELECT #SQL = 'SELECT CID,DOB, NAME,' + QUOTENAME(#Scname, '''') + ' from ' + #TableName
My page has a dropdown list that let a user choose any search category like title, description and so forth. So I have this SQL statement:
select * from table where "selected value from dropdown list" = "searchform"
I would like to pass it to the prepared statement like this:
select * from table where ? = ?
Since my select statements have the same form, only the columns in the where clause are different, is there a way to do this without manually creating select statements for every column?
Yes, it is called dynamic sql.
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + #column + ' = ''' + #value + ''''
EXEC(#sql)
You must check if the column is of numeric type.
You should also be careful for sql injection. My example is a very simplistic one, so you have to do your own checks.
For instance use of QUOTENAME would be useful:
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + QUOTENAME(#column) + ' = ''' + #value + ''''
EXEC(#sql)
The above examples are simply TSQL. In your prepared statement i think you could have the following:
PreparedStatement pstmt = con.prepareStatement("
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + QUOTENAME(?) + ' = ? '
EXEC(#sql)
");
pstm.setString(1,columnName);
pstm.setString(2,filterValue);
Unfortunately i am not familiar with JAVA, so i have not tested this. I think it worths a try though.
The above #sql variable will produce a statement like :
select * from table where [columnname] = filtervalue
columnname wrapped with brackets will help against SQL injection.
In a stored procedure I dynamically create a temp table by selecting the name of applications from a regular table. Then I add a date column and add the last 12 months. The result looks like this:
So far so good. Now I want to update the data in columns by querying another regular table. Normally it would be something like:
UPDATE ##TempTable
SET [columName] = (SELECT SUM(columName)
FROM RegularTable
WHERE FORMAT(RegularTable.Date,'MM/yyyy') = FORMAT(##TempMonths.x,'MM/yyyy'))
However, since I don't know what the name of the columns are at any given time, I need to do this dynamically.
So my question is, how can I get the column names of a temp table dynamically while doing an update?
Thanks!
I think you can use something like the following.
select name as 'ColumnName'
from tempdb.sys.columns
where object_id = object_id('tempdb..##TempTable');
And then generate dynamic sql using something like the following.
DECLARE #tableName nvarchar(50)
SET #tableName = 'RegularTable'
DECLARE #sql NVARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + ' UPDATE ##TempTable ' + CHAR(13) +
' SET [' + c.name + '] = (SELECT SUM([' + c.name + ']) ' + CHAR(13) +
' FROM RegularTable' + CHAR(13) +
' WHERE FORMAT(RegularTable.Date,''MM/yyyy'') = FORMAT(##TempMonths.x,''MM/yyyy''));' + CHAR(13)
from tempdb.sys.columns c
where object_id = object_id('tempdb..##MyTempTable');
print #sql
-- exec sp_executesql #sql;
Then print statement in above snippet shows that the #sql variable has the following text.
UPDATE ##TempTable
SET [Test Application One] = (SELECT SUM([Test Application One])
FROM RegularTable
WHERE FORMAT(RegularTable.Date,'MM/yyyy') = FORMAT(##TempMonths.x,'MM/yyyy'));
UPDATE ##TempTable
SET [Test Application Two] = (SELECT SUM([Test Application Two])
FROM RegularTable
WHERE FORMAT(RegularTable.Date,'MM/yyyy') = FORMAT(##TempMonths.x,'MM/yyyy'));
So now, you use sp_exec to execute the updates as follows (un-comment it from above snippet).
exec sp_executesql #sql;
If it's a 1 time UPDATE you can PRINT the dynamic SQL statement (as shown above) and then execute it in the SSMS Query Windows.
I recommend you use the print statement first to make sure the UPDATE statements generated are what you want, and then do the sp_executesql or run the printed UPDATE statement in the query window.
I'm quite new to SQL Server so hopefully this makes sense :)
I'm trying to declare variables to be used in an INNER JOIN.
If you take a look at my code, you'll see what I'm trying to do, without me needing to go into too much detail. Let me know if you need more info. Is that syntax possible?
EDIT: See new attempt below
--State - If suburb/postcode, could use postcode lookup
Declare #Missing as nvarchar(255),
#MissingUpdate as nvarchar(255),
#MatchA as nvarchar(255),
#MatchB as nvarchar(255),
#Reason as nvarchar(255);
Set #Missing = '[StateEXPORT]'; -- field to update
Set #MissingUpdate = '[State]'; -- field in postcode lookup to pull in
Set #MatchA = '[PostcodeEXPORT]'; -- field in master field to match with
Set #MatchB = '[Pcode]'; -- field in postcode lookup to match with
Set #Reason = 'Contactable - Needs verificiation - #MissingUpdate taken from Lookup'; -- reason here
update [BT].[dbo].[test]
set #Missing = b.#MissingUpdate,
FinalPot = #Reason
FROM [BT].[dbo].[test] a
INNER JOIN [BT].[dbo].[Postcode Lookup] b
ON a.#MatchA = b.#MatchB
where (#Missing is null or #Missing = '0') and [AddressSource] != ('Uncontactable')
GO
EDIT: SECOND ATTEMPT:
set #sql = 'update [BT].[dbo].[test] set ' + quotename(#Missing) + '= b.' + quotename(#MissingUpdate) + ', FinalPot = ' + #Reason + 'FROM [BT].[dbo].[test] a INNER JOIN [BT].[dbo].[Postcode Lookup] b ON a.' + quotename(#MatchA) + ' = b.' + quotename(#MatchB) + 'where (' + quotename(#Missing) + 'is null or' + quotename(#Missing) + ' = 0 and [AddressSource] != "(Uncontactable)"'
exec (#sql)
Thanks for your help,
Lucas
No, this syntax is not possible, at least not directly: you need to specify the column name, not a string variable that has the name.
If you wish to decide the names of columns dynamically, you could make a SQL string that represents the statement that you wish to execute, and pass that string to EXECUTE command. You have to take extra care not to put any of the user-entered data into the generated SQL string, though, to avoid SQL injection attacks.
EDIT: The reason your second attempt may be failing is that you are passing names in square brackets to quotename. You should remove brackets from your variable declarations, like this:
Set #Missing = 'StateEXPORT'; -- field to update
Set #MissingUpdate = 'State'; -- field in postcode lookup to pull in
Set #MatchA = 'PostcodeEXPORT'; -- field in master field to match with
Set #MatchB = 'Pcode'; -- field in postcode lookup to match with
You can't use variable names as column names without dynamic SQL.
An example of a dynamic SQL query:
declare #ColumnName varchar(100) = 'col1'
declare #sql varchar(max)
set #sql = 'select ' + quotename(#ColumnName) + ' from dbo.YourTable'
exec (#sql)
I have a database table that was imported from a csv file which had NULL in it, so that when it was imported instead of fields being NULL they contain the string value 'NULL'.
The CSV file is to big to open in a text editor to edit out all of the NULL so I am trying to create a SQL query to update each column of the table.
So far I have this
Alter PROCEDURE [dbo].[sp_fixnulls]
#column nvarchar(100)
AS
BEGIN
SET NOCOUNT ON;
UPDATE my_table
SET #column=''
WHERE #column = 'NULL'
END
---------------
sp_fixnulls (SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='my_table')
but this is not working. I get the error message
Msg 201, Level 16, State 4, Procedure sp_fixnulls, Line 0
Procedure or function 'sp_fixnulls' expects parameter '#column', which was not supplied.
#column is a variable. It cannot dynamically swap out its contents into SQL. You need to use TSQL to accomplish this, whereby you generate the SQL into a string then execute it. Such as:
DECLARE #sql VARCHAR(MAX)
SET #sql = '
UPDATE my_table
SET ' + #column + '=''''
WHERE ' + #column + ' = ''NULL''
'
EXEC (#sql) -- don't forget the parentheses
A small note that my code sets the column to empty string, which is NOT the same as NULL. I went with your existing example. If you want NULL, then
SET ' + #column + '= NULL
'Msg 201, Level 16, State 4, Procedure sp_fixnulls, Line 0 Procedure or function 'sp_fixnulls' expects parameter '#column', which was not supplied.'
The error you're getting is because you're trying to pass a select statement as a parameter to a stored procedure. If you were to pass just the name of one column to the stored procedure, you would get past that error.
Then you wouldn't get another error, but you wouldn't get the result you want. If you fix your stored procedure as Eli recommended (with the addition of parentheses around #sql in the EXEC statement, as I commented), it will work.
Then you'll need to wrap your stored procedure with a cursor (which most people don't recommend, but works when needed). Alternatively, you can just select all of the column names and generate a bunch of execute statements, and then run the statements.
SELECT 'EXECUTE sp_fixnulls N''' + column_name + ''';'
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'my_table';
This will generate statements like the following (assuming the table has columns id, name, and date).
EXECUTE sp_fixnulls N'id';
EXECUTE sp_fixnulls N'name';
EXECUTE sp_fixnulls N'date';
Another option is to forgo the stored procedure altogether.
SELECT 'UPDATE my_table SET ' + column_name
+ ' = NULL WHERE ' + column_name + ' = ''NULL'';'
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'my_table';
This will generate statements like the following.
UPDATE my_table SET id = NULL WHERE id = 'NULL';
UPDATE my_table SET name = NULL WHERE name = 'NULL';
UPDATE my_table SET date = NULL WHERE date = 'NULL';