Variable value was lost when while loop finished - sql

I want to set some default values to some table by using dynamic SQL in SQL Server, so I write 2 while loop, one is for tables and one is for columns in that table. so the outer loop is used to iterate table and the inner loop is used to iterate columns according to different data types the default will vary from one to other. So I need to catenate strings to build the dynamic SQL, please see my code below:
DECLARE #V_TABLE_LIST TABLE (TABLE_NAME VARCHAR(300))
DECLARE #V_COLUMN_LIST TABLE (TABLE_NAME VARCHAR(300), COLUMN_NAME VARCHAR(300), DATA_TYPE VARCHAR(300))
DECLARE #V_TABLE_NAME VARCHAR(300)
DECLARE #V_TABLE_NAME2 VARCHAR(300)
DECLARE #V_COLUMN_NAME VARCHAR(300)
DECLARE #V_DATA_TYPE VARCHAR(300)
DECLARE #V_SQL_ENABLE_IDENTITY_INSERT VARCHAR(200)
DECLARE #V_SQL_INSERT VARCHAR(3500)
DECLARE #V_SQL_COLUMN_LIST_NAME VARCHAR(3000)
DECLARE #V_SQL_COLUMN_LIST_VALUE VARCHAR(3000)
DECLARE #V_SQL_DISABLE_IDENTITY_INSERT VARCHAR(200)
INSERT INTO #V_TABLE_LIST
(TABLE_NAME)
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'DIM%' AND TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME NOT IN ('DIM_DATE') AND TABLE_NAME = 'DIM_ASSET'
--loop through each table
WHILE (SELECT COUNT(*) FROM #V_TABLE_LIST) > 0
BEGIN
SELECT TOP 1
#V_TABLE_NAME = TABLE_NAME
FROM #V_TABLE_LIST
--PRINT(#V_TABLE_NAME)-------------
SET #V_SQL_ENABLE_IDENTITY_INSERT = 'SET IDENTITY_INSERT ' + #V_TABLE_NAME + ' ON'
SET #V_SQL_DISABLE_IDENTITY_INSERT = 'SET IDENTITY_INSERT ' + #V_TABLE_NAME + ' OFF'
--load column info into #v_column_list table variable for each table
INSERT INTO #V_COLUMN_LIST
(TABLE_NAME, COLUMN_NAME, DATA_TYPE)
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #V_TABLE_NAME
SET #V_SQL_INSERT = ''
SET #V_SQL_COLUMN_LIST_NAME = ''
SET #V_SQL_COLUMN_LIST_VALUE = ''
--loop through each column for each table
WHILE (SELECT COUNT(*) FROM #V_COLUMN_LIST) > 0
BEGIN
SELECT TOP 1
#V_TABLE_NAME2 = TABLE_NAME
,#V_COLUMN_NAME = COLUMN_NAME
,#V_DATA_TYPE = DATA_TYPE
FROM #V_COLUMN_LIST
SET #V_SQL_COLUMN_LIST_NAME = #V_SQL_COLUMN_LIST_NAME + #V_COLUMN_NAME + ' --' + #V_DATA_TYPE +CHAR(10) + ','
SET #V_SQL_COLUMN_LIST_VALUE = #V_SQL_COLUMN_LIST_VALUE +
CASE WHEN #V_DATA_TYPE IN ('VARCHAR','NVARCHAR','CHAR', 'NCHAR') THEN '''UNKNOWN'''
WHEN #V_DATA_TYPE IN ('bigint', 'INT', 'smallint', 'DECIMAL','NUMERIC','MONEY','SMALLMONEY') THEN '-1'
WHEN #V_DATA_TYPE IN ('BIT', 'TINYINT') THEN NULL
WHEN #V_DATA_TYPE IN ('DATE', 'DATETIME','SMALLDATETIME','DATETIMEOFFSET','DATETIME2') THEN '''1957-01-01'''
ELSE ''
END + ' --' + #V_COLUMN_NAME + CHAR(10) + ','
DELETE FROM #V_COLUMN_LIST WHERE TABLE_NAME = #V_TABLE_NAME2 AND COLUMN_NAME = #V_COLUMN_NAME
--PRINT(#V_SQL_COLUMN_LIST_VALUE)
END
PRINT(#V_SQL_COLUMN_LIST_NAME)
PRINT(#V_SQL_COLUMN_LIST_VALUE)
--PRINT(#V_SQL_ENABLE_IDENTITY_INSERT)
SET #V_SQL_INSERT = 'INSERT INTO ' + #V_TABLE_NAME + CHAR(10)
+ '('
+ #V_SQL_COLUMN_LIST_NAME
+ ')'
+ ' VALUES ' + CHAR(10)
+ '(' + CHAR(10)
+ #V_SQL_COLUMN_LIST_VALUE
+ ')'
--PRINT(#V_SQL_INSERT)
--PRINT(#V_SQL_DISABLE_IDENTITY_INSERT)
DELETE FROM #V_COLUMN_LIST
DELETE FROM #V_TABLE_LIST WHERE TABLE_NAME = #V_TABLE_NAME
END
I added 2 print statements:
PRINT(#V_SQL_COLUMN_LIST_NAME) ---the concatenated field list can be printed out normally
PRINT(#V_SQL_COLUMN_LIST_VALUE) ---cannot print concatenated default value list , why?
as you can see the two print statements are the next step for the finishing of inner loop, but the first print statement can print out the something and the second one is empty, I checked the code a long time, I cannot find why the second print statement output empty string. Any logic errors in the code above?

This row sets the entire result to NULL if any column of BIT or TINYINT type is met.
WHEN #V_DATA_TYPE IN ('BIT', 'TINYINT') THEN NULL
Should be
WHEN #V_DATA_TYPE IN ('BIT', 'TINYINT') THEN 'NULL'
the same way as any other constant in a dynamic sql.

Related

Add new column to all tables in database

I'm trying to figure out if there's a quick way or single query to add a new column to all tables in database.
Right now I'm doing this for each table
ALTER TABLE [dbo].[%TABLE_NAME%] ADD %COLUMN_NAME% DATATYPE NOT NULL DEFAULT %VALUE%;
Is there a procedure or query I can make in AzureDataStudio to add a new column to all tables with the same name and default value.
select 'ALTER TABLE ' + QUOTENAME(SCHEMA_NAME([schema_id])) + '.' + QUOTENAME([name])
+ ' ADD %COLUMN_NAME% DATATYPE NOT NULL DEFAULT %VALUE%;'
from sys.tables
Create the statements you need with the above then run them.
I'd personally create a loop with dynamic SQL which gets executed as it is ran. The code below creates a temp table which is utilized for the loop which will iterate through each table listed in the temp table based on a calculated row number. The dynamic SQL is then set and executed.
Once you make the necessary changes, putting in your database name, column name, data type, and default value and you are satisfied with the results that get printed, you can un-comment the EXECUTE(#SQL) and re-run the script and it will add the new column to all your tables.
USE [INSERT DATABASE NAME HERE]
GO
IF OBJECT_ID(N'tempdb..#TempSysTableNames') IS NOT NULL
BEGIN
DROP TABLE #TempSysTableNames
END;
DECLARE #ColumnName VARCHAR(250) = 'INSERT COLUMN NAME HERE'
,#DataType VARCHAR(250) = 'INSERT DATA TYPE HERE'
,#DefaultValue VARCHAR(250) = 'INSERT DEFAULT VALUE HERE'
,#SQL VARCHAR(8000)
,#MaxRowNum INT
,#I INT = 1;
SELECT '[' + DB_NAME() + '].[' + OBJECT_SCHEMA_NAME([object_id],DB_ID()) + '].[' + name + ']' AS [name]
,ROW_NUMBER() OVER (ORDER BY [create_date]) AS RowNum
INTO #TempSysTableNames
FROM sys.tables
WHERE [type] = 'U';
SET #MaxRowNum = (SELECT MAX(RowNum)
FROM #TempSysTableNames);
WHILE (#I <= #MaxRowNum)
BEGIN
SET #SQL = (SELECT 'ALTER TABLE ' + [name] + ' ADD ' + #ColumnName + ' ' + #DataType + ' NOT NULL DEFAULT ' + #DefaultValue + ';'
FROM #TempSysTableNames
WHERE RowNum = #I);
PRINT(#SQL);
--EXECUTE(#SQL);
SET #I += 1;
END;

Counting rows in the table which have 1 or more missing values

Could you please advise how to find the number of rows in the table which have 1 or more missing values? The missing values are represented in my table by question marks = '?'. The table has 15 columns and ~50k rows. When I run the following query for some of the columns I can receive some results:
SELECT
COUNT(*)
FROM table_name
WHERE column_name ='?'
However I have also columns which bring me result: "Error converting data type varchar to float"
I would like to be able to find the number of rows in the table which have 1 or more missing values using 1 query/not run separately for each column.
Thank you in advance for your support!
Select Count(*)
From mySchema.myTable
Where Cast(Col1 As NVarChar(128)) +
Cast(Col2 As NVarChar(128)) +
Cast(Coln As NVarChar(128)) Like '%?%'
It's ugly and WILL be slow and you may need to modify the Casts accordingly, but should do the trick.
This should work for any column:
select count(*)
from table_name
where column_name is null or cast(column_name as varchar(255)) = '?';
Try following query:
Just set table name and it will get all columns
Also you can give value_to_match like '?' in your case or any other if you want.
DECLARE #table_name nvarchar(max) = 'table_name'
DECLARE #value_to_match nvarchar(max) = '1'
DECLARE #query nvarchar(max) = ''
DECLARE #Condition nvarchar(max) = ' OR ' -- 1 OR when you want to count row if any column has that value -- 2 when you want all all columns to have same value
SELECT #query = #query + ' cast(' + COLUMN_NAME + ' as nvarchar(500)) = ''' + #value_to_match + '''' + #Condition FROM informatioN_schema.columns WHERE table_name = #table_name
if ##rowcount = 0
BEGIN
SELECT 'Table doesn''t Exists'
RETURN
END
SELECT #query = LEFT(#query,LEN(#query)-3)
PRINT ('select count(9) FROM ' + #table_name + ' WHERE ' + #query)
EXEC ('select count(9) FROM ' + #table_name + ' WHERE ' + #query)

select columns with value NA

How to select columns in a table that only contain a specific value for all the rows? I am trying to find these columns to do an update on those values with a NULL value. In my columns I have varied range of values including NA
I am using SQL Server 2012.
I've tried doing: thsi only gives me column names. Can i add to this condition for columns with value 'NA'?
SELECT COLUMN_NAME AS NAMES,COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'ABC'
I am a beginner in SQL. Trying to figure out how to do this.
If min of column equals to max then that column contains same values:
Select
case when min(col1) = max(col1) then 1 else 0 end as Col1IsSame,
case when min(col2) = max(col2) then 1 else 0 end as Col2IsSame,
...
from Table
With dynamic query:
declare #s nvarchar(max) = 'select '
select #s = #s + 'case when min(' + COLUMN_NAME + ') = max(' +
COLUMN_NAME + ') then 1 else 0 end as ' + COLUMN_NAME + ','
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Table'
Set #s = substring(#s, 1, len(#s) - 1) + ' from Table'
exec(#s)
TRY THIS QUERY
DECLARE #SQLQUERY NVARCHAR(MAX)
declare #tableName varchar(50)
DECLARE #NAME VARCHAR(50)
Declare #ParamDefinition AS NVarchar(2000)
Set #ParamDefinition = '#OIM VARCHAR(20)'
SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM
set #tableName= (SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM)
SET #NAME=(SELECT C.NAME
FROM sys.columns c
JOIN
sys.tables t ON c.object_id = t.object_id
WHERE c.name in (select distinct name
from sys.columns
where object_id=#OIM))
SET #SQLQUERY = ''
SELECT #SQLQUERY = #SQLQUERY + 'UPDATE ' + #tableName + ' SET ' + #NAME + ' = NULL WHERE ' + #NAME + ' = NA ; '
PRINT #SQLQUERY
Execute sp_Executesql #SQLQUERY , #ParamDefinition, #OIM
end

quickest way to update a table to set blank values to NULLs?

I have a table and there are blank values in several columns, scattered all over the place.
I want to replace '' with NULL.
What's the quickest way to do this? Is there a trick I'm not aware of?
update <table name> set
<column 1> = case when <column 1> = '' then null else <column 1> end,
<column 2> = case when <column 2> = '' then null else <column 2> end
you can add as many lines as you have columns. No need for a where clause (unless you have massive amounts of data - then you may want to add a where clause that limits it to rows that have empty values in each of the columns you are checking)
If you have a lot of columns and you don't want to write the SQL manually, you can use the Information_Schema.Columns view to generate the SQL for you...
DECLARE #Table AS Varchar(100)
SET #Table = 'Your Table'
SELECT 'UPDATE ' + #Table + ' SET ' + QUOTENAME(Column_Name)
+ ' = NULL WHERE ' + QUOTENAME(Column_Name) + ' = '''''
FROM Information_Schema.Columns
WHERE Table_Name = #Table
AND Data_Type IN ( 'varchar', 'nvarchar' )
Then just copy the result set and run it in a new query window...
I did it like this:
DECLARE #ColumnNumber INT
DECLARE #FullColumnName VARCHAR(50)
DECLARE #SQL NVARCHAR(500)
SET #ColumnNumber = 0
WHILE (#ColumnNumber <= 30)
BEGIN
SET #FullColumnName = 'Column' + CAST(#ColumnNumber AS VARCHAR(10))
SET #SQL = 'UPDATE [].[].[] SET ' + #FullColumnName + ' = NULL WHERE ' + #FullColumnName + ' = '''''
EXECUTE sp_executesql
#SQL;
SET #ColumnNumber = #ColumnNumber + 1
END
This expands on JJ.'s answer. I had a table where there were there were more columns than I cared to count and I wanted to make sure that every column that had blanks were converted to nulls.
DECLARE #tableName VARCHAR(50) = 'MyTable'
DECLARE #colIndex INT = 0
DECLARE #colName VARCHAR(50)
DECLARE #sql NVARCHAR(MAX)
DECLARE #maxColCount INT = (SELECT COUNT(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName)
WHILE (#colIndex <= #maxColCount)
BEGIN
SELECT #colName = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName AND ORDINAL_POSITION = #colIndex
SET #sql = 'UPDATE [dbo].[' + #tableName + '] SET ' + #colName + ' = NULL WHERE ' + #colName + ' = '''''
EXEC sp_executesql #sql
PRINT('Updated column ' + #colName)
SET #colIndex = #colIndex + 1
END

SQL To search the entire MS SQL 2000 database for a value

I would like to search an entire MS SQL 2000 database for one value. This would be to aid development only. Keep that in mind when considering this question.
This will get all the table names and the column of the data type I'm looking for:
SELECT Columns.COLUMN_NAME, tables.TABLE_NAME
FROM INFORMATION_SCHEMA.Columns as Columns
JOIN INFORMATION_SCHEMA.TABLES as tables
On Columns.TABLE_NAME = tables.TABLE_NAME
WHERE Columns.DATA_TYPE = 'INT'
I was thinking something like this:
-- Vars
DECLARE #COUNTER INT
DECLARE #TOTAL INT
DECLARE #TABLE CHAR(128)
DECLARE #COLUMN CHAR(128)
DECLARE #COLUMNTYPE CHAR(128)
DECLARE #COLUMNVALUE INT
-- What we are looking for
SET #COLUMNTYPE = 'INT'
SET #COLUMNVALUE = 3
SET #COUNTER = 0
-- Find out how many possible columns exist
SELECT #TOTAL = COUNT(*)
FROM INFORMATION_SCHEMA.Columns as Columns
JOIN INFORMATION_SCHEMA.TABLES as tables
On Columns.TABLE_NAME = tables.TABLE_NAME
WHERE Columns.DATA_TYPE = #COLUMNTYPE
PRINT CAST(#TOTAL AS CHAR) + 'possible columns'
WHILE #COUNTER < #TOTAL
BEGIN
SET #COUNTER = #COUNTER +1
-- ADD MAGIC HERE
END
Any ideas?
UPDATE I recently found this tool that works quite well.
Since it is dev only (and probably doesn't have to be very elegant), how about using TSQL to generate a pile of TSQL that you then copy back into the query window and execute?
SELECT 'SELECT * FROM [' + tables.TABLE_NAME + '] WHERE ['
+ Columns.Column_Name + '] = ' + CONVERT(varchar(50),#COLUMNVALUE)
FROM INFORMATION_SCHEMA.Columns as Columns
INNER JOIN INFORMATION_SCHEMA.TABLES as tables
On Columns.TABLE_NAME = tables.TABLE_NAME
WHERE Columns.DATA_TYPE = #COLUMNTYPE
It won't be pretty, but it should work... an alternative might be to insert something like the above into a table-variable, then loop over the table-variable using EXEC (#Sql). But for dev purposes it probably isn't worth it...
I've found this script to be helpful... but as Marc noted, it wasn't really worth it. I've only used it a handful of times since I wrote it six months ago.
It only really comes in handy because there are a couple of tables in our dev environment which cause binding errors when you query them, and I always forget which ones.
BEGIN TRAN
declare #search nvarchar(100)
set #search = 'string to search for'
-- search whole database for text
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IF nullif(object_id('tempdb..#tmpSearch'), 0) IS NOT NULL DROP TABLE #tmpSearch
CREATE TABLE #tmpSearch (
ListIndex int identity(1,1),
CustomSQL nvarchar(2000)
)
Print 'Getting tables...'
INSERT #tmpSearch (CustomSQL)
select 'IF EXISTS (select * FROM [' + TABLE_NAME + '] WHERE [' + COLUMN_NAME + '] LIKE ''%' + #search + '%'') BEGIN PRINT ''Table ' + TABLE_NAME + ', Column ' + COLUMN_NAME + ''';select * FROM [' + TABLE_NAME + '] WHERE [' + COLUMN_NAME + '] LIKE ''%' + #search + '%'' END' FROM information_schema.columns
where DATA_TYPE IN ('ntext', 'nvarchar', 'uniqueidentifier', 'char', 'varchar', 'text')
and TABLE_NAME NOT IN ('table_you_dont_want_to_look_in', 'and_another_one')
Print 'Searching...
'
declare #index int
declare #customsql nvarchar(2000)
WHILE EXISTS (SELECT * FROM #tmpSearch)
BEGIN
SELECT #index = min(ListIndex) FROM #tmpSearch
SELECT #customSQL = CustomSQL FROM #tmpSearch WHERE ListIndex = #index
IF #customSql IS NOT NULL
EXECUTE (#customSql)
SET NOCOUNT ON
DELETE #tmpSearch WHERE ListIndex = #index
SET NOCOUNT OFF
END
print 'the end.'
ROLLBACK