Update null value to a column in dynamic SQL - sql

I need to update a specific set of columns with null value, but when I'm trying to pass null value to dynamic SQL I'm not getting any error or output.
DECLARE #Value VARCHAR(100)
SELECT #Value = null
DECLARE #TableName VARCHAR(1000),#ColumnName VARCHAR(100)
DECLARE #Sql NVARCHAR(MAX)
SET #Sql= N''
DECLARE UpdatePlantId_Crsr CURSOR
STATIC FOR
SELECT ST.name AS TableName,SC.name AS ColumnName
FROM
sys.columns SC
INNER JOIN
sys.tables ST ON ST.object_Id = SC.Object_Id
WHERE
SC.name like '%_MLP'
--AND ST.name not like 'tPlant'
OPEN UpdatePlantId_Crsr
IF ##CURSOR_ROWS > 0
BEGIN
FETCH NEXT FROM UpdatePlantId_Crsr INTO #TableName,#ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Sql= N''
SELECT #Sql = #Sql + N' UPDATE '+#TableName +' SET '+#ColumnName+ '= '+ #Value +'
'
PRINT #Sql
--EXEC(#Sql)
FETCH NEXT FROM UpdatePlantId_Crsr INTO #TableName,#ColumnName
END
END
CLOSE UpdatePlantId_Crsr
DEALLOCATE UpdatePlantId_Crsr

I suspect that something is wrong with your application if you need to use dynamic SQL to set tables and columns to NULL. That said, the question can still be answered.
You should use sp_executesql. But given that the table and column names cannot be passed in, just set up the SQL correctly:
SET #Sql = N'UPDATE ' + #TableName + ' SET ' + #ColumnName + ' = NULL' ;
EXEC sp_executesql #sql; -- yuo can still use it with no parameters
I am not sure why you are concatenating the #sql string, so I removed that.
Note that + NULL returns NULL -- both for string concatenation and addition.

Related

IF EXISTS does not return correct result

I have to check if a column in my sql table has null values and to print 'Yes'/'No'
DECLARE #columnName nvarchar(50)
SET #columnName = 'City'
IF EXISTS (SELECT 1 FROM rf.Country WHERE #columnName IS NULL)
BEGIN
PRINT 'Yes'
END
ELSE
BEGIN
PRINT 'No'
END
This query returns 'No' when I know for sure that there are null values in this column. I see that it is not allowed to use #var in WHERE statement but I need a way to loop through all columns in a table and to print result for each column if it contains NULL values.
You need to safely inject the value into a dynamic query, and then execute that:
DECLARE #ColumnName sysname; --synonym for nvarchar(128) NOT NULL
SET #ColumnName = N'City';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = CHAR(13) + CHAR(10);
SET #SQL = N'IF EXISTS (SELECT 1 FROM rf.Country WHERE ' + QUOTENAME(#ColumnName) + N' IS NULL)' + #CRLF +
N' PRINT N''Yes'';' + #CRLF +
N'ELSE' + #CRLF +
N' PRINT N''No'';';
--PRINT #SQL; --Your debugging friend
EXEC sys.sp_executesql #SQL;
Your query is not checking the column values in the table. It is just checking the constant -- and #columnName IS NULL always evaluates to false because #columnName has a value.
You would need to use dynamic SQL. Perhaps:
DECLARE #columnName nvarchar(50)
SET #columnName = 'City';
SET #SQL = '
SELECT (CASE WHEN EXISTS (SELECT 1 FROM rf.Country WHERE #columnName IS NULL)
THEN 1 ELSE 0
END) as flag
';
SET #SQL = REPLACE(#SQL, '#columnName', #columnName)
DECLARE #flag INT;
EXEC sp_executeSQL #SQL,
N'#flag int OUTPUT',
#flag=#flag OUTPUT;
IF #flag = 1
PRINT 'Yes';
ELSE
PRINT 'No';
In general, I would discourage you from writing code where you need to pass column names around like this. That usually indicates a problem with the data model. I should say "usually". Under some circumstances, this can be convenient.

Loop through Query and Update field

I'm trying to loop through a fields defined in a query to an update statement.
I have the following SQL:
Declare #SQL varchar(max)
#SQL= 'Select [a],[b],[c],[d],[e]....[z]
From Table1;'
I want to be able to loop through all the fields [a]-[z] and update via the following statement:
Update Table 1
Set [a] = Case when [a] = 'Not at all' Then 0
when [a] = 'Very Much' Then 10 End
Field names are not actually [a]..[z]; I can't run the the update statement on the whole table, only a specific set of field names.
Struggling to write it programatically in SQL Server.
Declare #SQL varchar(max)
Declare #name varchar(100)
DECLARE #getid CURSOR
Set #getid = cursor for
SELECT name
FROM
sys.dm_exec_describe_first_result_set('Select [a],[b],[c],[d],[e]....[z]
From Table1', NULL, 0)
Open #getid
FETCH NEXT
FROM #getid INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'Update Table1
Set ' + #name + ' = Case when ' + #name +'= ''Very Much'' Then ''10''
when ' + #name + ' = ''Not at all'' Then ''0''
Else ' + #name + ' End'
Exec(#SQL)
FETCH NEXT
FROM #getid INTO #name
END
CLOSE #getid
DEALLOCATE #getid
Basically dm_exec_describe_first_result_set is grabbing the fieldnames and outputting it as a recordset. Then we are just passing the the each of the records to #name and use it form our update statement and then executing it for each record passed.
Hope this helps someone else! Curious to see if there is a better way.
I think if you want to make it a little more generic I would do something like the following code. This will allow you to not have to write the specific query for every table you want to do this to and you could potentially filter out columns you do not want in the future.
To be clear, I borrowed the SQL to do the actual UPDATE from #Dale-K post and just made it pretty.
DECLARE #strSQL NVARCHAR(1000)
DECLARE #strTable NVARCHAR(100)
DECLARE #strColName VARCHAR(100)
SET #strTable = N'Table1'
CREATE TABLE #COLUMNS(ColName varchar(100))
SET #strSQL = ' select COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and DATA_TYPE in (''nvarchar'', ''varchar'')'
INSERT INTO #COLUMNS
EXEC sp_executeSQL #strSQL, N'#TableName nvarchar(100)', #TableName = #strTable
DECLARE csrColumns CURSOR LOCAL FORWARD_ONLY FOR
SELECT ColName FROM #COLUMNS
OPEN csrColumns
FETCH csrColumns INTO #strColName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #strSQL = N'UPDATE ' + #strTable + '
SET ' + #strColName + ' = CASE WHEN ' + #strColName +'= ''Very Much'' THEN ''10''
WHEN ' + #strColName + ' = ''Not at all'' THEN ''0''
ELSE ' + #strColName + ' END'
exec sp_ExecuteSQL #strSQL
FETCH csrColumns INTO #strColName
END
CLOSE csrColumns
DEALLOCATE csrColumns

Information_schema.columns in the query

I need to pull the data from custom columns in all tables which have "custom1, custom2, custom3....." columns.
Declare #TableName varchar(max)
set #TableName = 'RandomTable';
with main as
(
select distinct
infos.COLUMN_NAME, infos.TABLE_NAME
from
INFORMATION_SCHEMA.COLUMNS infos
where
infos.TABLE_NAME = #TableName
and infos.COLUMN_NAME like 'Custom%%'
)
This query returns the list of custom columns in any table I specify in the parameter. Any idea how to use that in the query so I can get all the data from the RandomTable.Custom%% columns?
Any idea? I'm loosing the plot on it.
Following incomudro idea and guessing you are using SQL Server you could do something like this:
DECLARE
#TableName VARCHAR(MAX)
,#ColumnName VARCHAR(MAX)
,#SQLQuery VARCHAR(MAX)
,#FirstFlag BIT
SET #TableName = 'TEST'
SELECT
COL.COLUMN_NAME
INTO ##CUSTOM_COL
FROM INFORMATION_SCHEMA.COLUMNS COL
WHERE 1 = 1
AND COLUMN_NAME LIKE 'CUSTOM__'
AND TABLE_NAME = #TableName
DECLARE CUR_CUSTOM_COL CURSOR FOR
SELECT * FROM ##CUSTOM_COL
OPEN CUR_CUSTOM_COL
FETCH NEXT FROM CUR_CUSTOM_COL INTO #ColumnName
SET #FirstFlag = 1
SET #SQLQuery = 'SELECT *'
WHILE ##FETCH_STATUS = 0
BEGIN
IF #FirstFlag = 0
BEGIN
SET #SQLQuery = #SQLQuery + ', '
END
SET #SQLQuery = #SQLQuery + #ColumnName
SET #FirstFlag = 0
FETCH NEXT FROM CUR_CUSTOM_COL INTO #ColumnName
END
CLOSE CUR_CUSTOM_COL
DEALLOCATE CUR_CUSTOM_COL
SET #SQLQuery = #SQLQuery + ' FROM ' + #TableName
EXEC(#SQLQuery)
I saved my workspace in this fiddle. Unfortunaly it doesnt work there as intendet, but it should in your SQL Client(or I did a little typing mistake). With some little modifications you could not only display the custom columns from 1 specified table but from all tables. Also you could, besides selecting it, insert the ouput from the custom columns in temp tables.

Remove quotation marks from all columns in SQL Server

I have a table with three columns: A, B and C.
A ; B; C
"a1"; "b1"; "c1"
"a2"; "b2"; "c3"
"a3"; "b3"; "c3"
I need to remove the quotation marks from all rows in the table. In this post I found a solution which works but requires to specify the names of all columns:
UPDATE myTable
SET A = REPLACE(A, '"', '');
UPDATE myTable
SET B = REPLACE(B, '"', '');
UPDATE myTable
SET C = REPLACE(C, '"', '');
QUESTION: Is there a less verbose way to apply the replace to all columns? For example a one-line expression?
Thanks
There isn't a one line script for this but I have a few lines in my code when I get rid of all the double quotes in the stagging table once I have got my data into sql server, mind you all of these columns are varchar data type.
-- Get rid of double quotes in the data
Declare #ColName SYSNAME , #Sql Nvarchar(Max)
Declare Cur Cursor FOR
SELECT c.name
from sys.columns c inner join sys.tables t on c.object_id = t.object_id
Where t.name = 'myTable' --<-- Your Table name
OPEN Cur
FETCH NEXT FROM Cur INTO #ColName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'UPDATE myTable
SET ' + QUOTENAME(#ColName) + ' = LTRIM(RTRIM(ISNULL(REPLACE(' + QUOTENAME(#ColName) + ' , ''"'' , '''') , '''')))'
--PRINT #SQL
Exec sp_executesql #Sql
FETCH NEXT FROM Cur INTO #ColName
END
CLOSE Cur
DEALLOCATE Cur
GO
If number of records are not huge:-
You can script out the schema and data.
Replace the double quotes by Find and Replace All.
Run the cleaned script.
The below procedure will replace any single character with another single character in any table :)
USE [TSQL2012]--your database name
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE dbo.replace_char
#char_to_replace char(1), --character to be replaced
#expected_char char(1),
#table_name nvarchar(128) --your table name
AS
BEGIN
--Variable declaration
DECLARE #Column_Count_1 int
DECLARE #SQLString AS NVARCHAR(4000)
DECLARE #count int=1
DECLARE #column_name nvarchar(128)
--Getting the count of column
SET #SQLString=N'select #Column_Count=count(*) from '+ #table_name
EXEC sp_executesql #SQLString
, N'#Column_Count int OUTPUT'
, #Column_Count = #Column_Count_1 OUTPUT
--Getting the actual column names into a temporary table
select c.name as name
into #temp_column_names
from sys.tables t
join sys.columns c
on t.object_id=c.object_id
where t.name=#table_name
--Looping through each column to replace the required character
WHILE (#count<=#Column_Count_1)
BEGIN
--setting the column name
SET #column_name=(select top 1 name from
(select Row_number()over (order by name) as r_n_n, name
from #temp_column_names) aa
where r_n_n >=#count)
--updating the rows
SET #SQLString =N'Update ' + #table_name
SET #SQLString= #SQLString + N' Set ' + #column_name
SET #SQLString= #SQLString + N' = replace(' + #column_name
SET #SQLString =#SQLString + N',''' +#char_to_replace
SET #SQLString=#SQLString + N''',''' +#expected_char
SET #SQLString=#SQLString + N''');'
EXEC(#SQLString);
SET #count=#count+1;
END
--Dropping the temp table
DROP TABLE #temp_column_names
END
GO
Execution of the above procedure
EXEC dbo.replace_char #char_to_replace, #expected_char, #table_name
In your case
EXEC dbo.replace_char '"', '','Sample_1'
Sample_1 is the table which I created.

Best Way To Convert All "SMALLINT" Columns Within A Database Schema To "BIT"? (SQL)

How do I convert all smallint type columns from my database to bit types?
I am using SQL Server 2008.
In SQL Server you can do it with ALTER TABLE my_table ALTER COLUMN my_column [new_datatype].
Be careful of things like default values because I haven't tested with them.
Example 1 - will give a list of queries for you to review / amend / execute (safer option).
DECLARE #TableSchema VARCHAR(100)
DECLARE #TableName VARCHAR(100)
DECLARE #ColumnName VARCHAR(100)
DECLARE #Query NVARCHAR(1000)
DECLARE #FromDataType NVARCHAR(50)
DECLARE #ToDataType NVARCHAR(50)
SET #TableSchema = 'dbo';
SET #FromDataType = 'smallint';
SET #ToDataType = 'bit';
DECLARE c CURSOR FAST_FORWARD FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME <> 'sysdiagrams'
AND DATA_TYPE = #FromDataType
OPEN c;
FETCH NEXT FROM c INTO #TableName, #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = N'ALTER TABLE ' + #TableName + N' ALTER COLUMN ' + #ColumnName + N' ' + #ToDataType -- + CHAR(13) + N'GO'
PRINT #Query
EXEC sp_EXECUTESQL #Query
FETCH NEXT FROM c INTO #TableName, #ColumnName;
END
CLOSE c;
DEALLOCATE c;
Example 2 - will execute (recommend running example 1 first!)
DECLARE #TableSchema VARCHAR(100)
DECLARE #TableName VARCHAR(100)
DECLARE #ColumnName VARCHAR(100)
DECLARE #Query NVARCHAR(1000)
DECLARE #FromDataType NVARCHAR(50)
DECLARE #ToDataType NVARCHAR(50)
SET #TableSchema = 'dbo';
SET #FromDataType = 'smallint';
SET #ToDataType = 'bit';
DECLARE c CURSOR FAST_FORWARD FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME <> 'sysdiagrams'
AND DATA_TYPE = #FromDataType
OPEN c;
FETCH NEXT FROM c INTO #TableName, #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = N'ALTER TABLE ' + #TableName + N' ALTER COLUMN ' + #ColumnName + N' ' + #ToDataType + CHAR(13) + N' GO'
PRINT #Query
FETCH NEXT FROM c INTO #TableName, #ColumnName;
END
CLOSE c;
DEALLOCATE c;
Please be careful doing this and test it on a backup database first. The following query will create ALTER statements for each column in your database that have SMALLINT datatype to convert them to BIT.
select 'ALTER TABLE ' + QUOTENAME(o.Name) + ' ALTER COLUMN ' + QUOTENAME(c.Name) + ' BIT' as Command
from sys.objects o
inner join sys.columns c
on o.object_id = c.object_id
where system_type_id = 52
and o.Type = 'U'
Also, be sure each column listed only contains 1 or 0 or you will get truncation errors when you run the script.
If you are asking about converting the column data type, I don't thing you can do that directly. You can add a new column as BIT and populate it from the old column, then drop the old column and rename the new one back to the old name.
See the online docs for more info.