In dynamic SQL, table is not being created - sql

I have to use the configurations table to create a table if the table_status is new, and I have written the code but the table 'Dimcampaign' is not being created.

Initially you set #Tablestatus to a SQL statement, but the while loop requires #Tablestatus = 'New'. You should change how you initialize your #Tablestatus variable so that the logic flows into the while loop.
I would guess that you actually want #Tablestatus to be initialized to the value in your dbo.configuration table. For example:
declare #Tablestatus varchar(MAX)
select #Tablestatus = tablestatus from dbo.configuration
That being said, your while loop does not have a way to terminate. For example, inside the loop you should reset #Tablestatus so that it can become something other than 'New' so the loop can end.
For example:
while #Tablestatus = 'New' begin
-- maybe do some stuff here
update dbo.configuration set tablestatus = 'Old'
-- maybe do some other stuff here
select #Tablestatus = tablestatus from dbo.configuration
end
Looking a little more at your post, I don't really understand why you have a while loop there. It looks like you want something like this:
-- Initialize variables with values from dbo.configuration
declare #Tablestatus varchar(MAX)
select #Tablestatus = tablestatus from dbo.configuration
declare #If_New_Table_then_PrimaryKey NVARCHAR(MAX)
select #If_New_Table_then_PrimaryKey = If_New_Table_then_PrimaryKey from dbo.configuration
declare #NewColumn varchar(max)
select #NewColumn = Newcolumn from dbo.configuration
declare #Datatypes NVARCHAR(MAX)
select #Datatypes = Datatypes from dbo.configuration
declare #sql varchar(100)
-- Now that your variables are initialized you
-- can use the variables to take the appropriate action
if #Tablestatus = 'New' and #If_New_Table_then_PrimaryKey = 'Yes'
begin
set #sql = 'Create table' + #tablename + '(' + #Newcolumn + #Datatypes + ' PRIMARY KEY' + '(' + #Newcolumn + ')' + ');'
print (#sql)
exec(#sql)
end
if #Tablestatus = 'Old'
begin
set #sql = 'Alter table' + #tablename + 'ADD' + #Newcolumn + #Datatypes
print (#sql)
exec(#sql)
end

I like playing around with cursors and dynamic SQL. Something like this should do the trick, I'd add a whole lot of checking though! What if tablename contains spaces (you might like to use QUOTENAME), or what if datatypes doesn't contain a valid datatype? Etc etc, I can think of 100 things that can go wrong. Generally, when you want to do this, you need to rethink your design. But I have been in situations where I had to do something similar.
DECLARE #Tablestatus NVARCHAR(4000)
, #tablename NVARCHAR(4000)
, #If_New_Table_then_PrimaryKey NVARCHAR(4000)
, #NewColumn NVARCHAR(4000)
, #Datatypes NVARCHAR(4000)
, #sql NVARCHAR(4000);
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT tablestatus
, tablename
, If_New_Table_then_PrimaryKey
, Newcolumn
, Datatypes
FROM dbo.configuration;
OPEN cur;
FETCH NEXT FROM cur
INTO #Tablestatus
, #tablename
, #If_New_Table_then_PrimaryKey
, #NewColumn
, #Datatypes;
WHILE ##FETCH_STATUS = 0
BEGIN;
IF #Tablestatus = 'New'
AND #If_New_Table_then_PrimaryKey = 'Yes'
BEGIN;
SET #sql = N'Create table ' + #tablename + N'(' + #NewColumn + N' ' + #Datatypes + N' PRIMARY KEY' + N'(' + #NewColumn + N')' + N');';
PRINT ( #sql );
EXEC sys.sp_executesql #sql;
END
IF #Tablestatus = 'Old'
BEGIN;
SET #sql = N'Alter table ' + #tablename + N'ADD ' + #NewColumn + N' ' +#Datatypes;
PRINT ( #sql );
EXEC sys.sp_executesql #sql;
END;
FETCH NEXT FROM cur
INTO #Tablestatus
, #tablename
, #If_New_Table_then_PrimaryKey
, #NewColumn
, #Datatypes
END;
CLOSE cur;
DEALLOCATE cur;

Related

Select from list of tables / multiple tables with nested query - MS SQL

Not sure if this has an easy answer, but I'm basically trying to do this:
select id
from (select table_name from information_schema.columns where column_name = 'id')
where id = 1234
So passing in a list of tables into the FROM.
I'm trying to check all tables where this column exists if they have a matching value for 1234.
And without typing 31 times, select from table1, select from table2, etc etc
And without doing a bunch of joins.
possible?
I wrote this stored procedure.
It SUCKS I know, I've never written anything in tsql (teesquill?) before, and my goal was just to get something that works.
// find all occurrences of value in DB
USE [your db here]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[usp_query] (
#value NVARCHAR(128),
#colName NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
-- DECLARE #tables NVARCHAR(MAX);
DECLARE #tabName NVARCHAR(MAX);
-- DECLARE #colName NVARCHAR(MAX);
DECLARE #count INT;
-- construct SQL
--SET #tables = N'SELECT Table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE "yourcollumn"'
DECLARE tabs CURSOR FOR SELECT table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE 'yourcollumn'
OPEN tabs
FETCH NEXT FROM tabs INTO #tabName
WHILE ##fetch_status = 0
BEGIN
--SET #count = N'SELECT count ( ' + #colName + ' ) FROM ' + #tabName + ' where ' + #colName + ' = ' + #value
DECLARE #SQLString NVARCHAR(500);
DECLARE #ParmDefinition NVARCHAR(500);
DECLARE #varOut NVARCHAR(25);
SET #SQLString = N'SELECT #count = count ( ' + #colName + ' ) FROM ' + #tabName + ' where ' + #colName + ' = ' + #value;
SET #ParmDefinition = N'#count NVARCHAR(25) OUTPUT';
EXECUTE sp_executesql #SQLString
,#ParmDefinition
,#count = #varOut OUTPUT;
SET #sql = N'SELECT ' + #colName + ' FROM ' + #tabName + ' where yourcollumn = ' + #value;
IF #varOut > 0
SELECT #tabName AS 'value found in table'
--EXEC sp_executesql #sql
FETCH NEXT FROM tabs INTO #tabName
END
CLOSE tabs
END;

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

Dynamic SQL and loop challenge, SQL Server 2012

I have n tables that is unknown before runtime with tablename always being tablename1, tablename2... tablenameN. The first column of each table is always Name. The challenge is to change that column name in each table to Name1, Name2.. NameN. I know I should be using sp_rename and a loop. Having trouble building up the query, I'm pretty new to SQL. Help would be appreciated. THanks
This should do the rename:
DECLARE #counter INT;
DECLARE #tableName NVARCHAR(100);
DECLARE #columnName NVARCHAR(100);
DECLARE #newColumnName NVARCHAR(100);
SET #counter = 1;
WHILE #counter < 65536
BEGIN
SET #tableName = 'tableName' + CAST(#counter AS NVARCHAR)
IF EXISTS(SELECT * FROM sys.tables WHERE name = #tableName)
BEGIN
SET #columnName = #tableName + N'.name';
SET #newColumnName = N'name' + CAST(#counter AS NVARCHAR);
EXEC sp_rename #objname=#columnName, #newName=#newColumnName;
END
ELSE
BEGIN
SET #counter = 65536
END
SET #counter = #counter + 1
END
It's a bit crude though.. and renames only 65535 tables and full amount only when there's none missing in between.
Uncomment sql_exec when you're sure it does what you're expecting :)
DECLARE #TableName sysname, #ColName sysname
DECLARE #num sysname
DECLARE #sql nvarchar(4000)
DECLARE cTables CURSOR FOR SELECT name from dbo.sysobjects where Category = 0 AND type NOT IN (N'F', N'FN', N'IF', N'TF', N'P', N'TR', N'V', N'K') AND name like 'tablename%'
OPEN cTables
FETCH NEXT FROM cTables INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #num = SUBSTRING(#Tablename, 10, 5)
SET #sql = N'sp_RENAME ''' + #TableName + '.[Name]'' , ''[Name' + #num + ']'', ''COLUMN'''
PRINT #sql
-- EXEC sp_sqlexec #sql
FETCH NEXT FROM cTables INTO #TableName
END
CLOSE cTables;
DEALLOCATE cTables;
Here's a SP - give it a try ;-)
CREATE PROCEDURE dbo.Rename
(
#n INT
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #Stmt NVARCHAR(MAX)
DECLARE #i INT
DECLARE #tabname NVARCHAR(MAX)
DECLARE #colname NVARCHAR(MAX)
SET #i = 1
WHILE #i <= #n
BEGIN
SET #tabname = N'tablename' + CAST(#i AS NVARCHAR(MAX))
SET #colname = N'name' + CAST(#i AS NVARCHAR(MAX))
IF EXISTS(SELECT TOP 1 1 FROM sys.tables t WHERE t.name = #tabname)
BEGIN
SET #Stmt = N'EXEC sp_rename ''' + #tabname + '.[name]'', ''' + #colname +''',''COLUMN'''
--PRINT #Stmt
EXEC sp_executesql #Stmt
END
SET #i = #i + 1
END
END

Quickest way to alter datatypes

A database needs to be upgraded and as part of the upgrade, I want to convert all TEXT/NTEXT fields in the dbo schema to the NVARCHAR(MAX) datatype. The data in those fields cannot be modified, though.
This upgrade needs to be done through an SQL Script!
So, how to do this?
(Without having to write ALTER TABLE bla ALTER COLUMN blabla NVARCHAR(MAX) blablabla...)
In the assumption you only use "system types" in your tables you can look up the columns with the types you want to change and call the updates in a cursor.
declare #nsql nvarchar(2000)
, #table sysname
, #column sysname
, #type sysname
, #is_nullable bit
declare cur cursor local read_only
for
select tableName = OBJECT_NAME([object_id]), columnName = name, type = TYPE_NAME(system_type_id), is_nullable from sys.columns where TYPE_NAME(system_type_id) in ('text', 'ntext')
open cur
fetch next from cur into #table, #column, #type, #is_nullable
WHILE (##FETCH_STATUS = 0)
BEGIN
select #nsql = N'ALTER TABLE ' + quotename(#table) + N' ALTER COLUMN ' + quotename(#column) + N' '
if #type = N'text'
select #nsql = #nsql + N' VARCHAR(MAX)'
if #type = N'ntext'
select #nsql = #nsql + N' NVARCHAR(MAX)'
if #is_nullable = 0
select #nsql = #nsql + N' NOT NULL'
exec(#nsql)
fetch next from cur into #table, #column, #type, #is_nullable
END
close cur
deallocate cur
If you also use "alias types" you will have to go through a bit more pain to fix them.

How do I do a simple 'Find and Replace" in MsSQL?

Question is pretty self explanitory. I want to do a simple find and replace, like you would in a text editor on the data in a column of my database (which is MsSQL on MS Windows server 2003)
The following query replace each and every a character with a b character.
UPDATE
YourTable
SET
Column1 = REPLACE(Column1,'a','b')
WHERE
Column1 LIKE '%a%'
This will not work on SQL server 2003.
like so:
BEGIN TRANSACTION;
UPDATE table_name
SET column_name=REPLACE(column_name,'text_to_find','replace_with_this');
COMMIT TRANSACTION;
Example: Replaces <script... with <a ... to eliminate javascript vulnerabilities
BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;
This pointed me in the right direction, but I have a DB that originated in MSSQL 2000 and is still using the ntext data type for the column I was replacing on. When you try to run REPLACE on that type you get this error:
Argument data type ntext is invalid for argument 1 of replace
function.
The simplest fix, if your column data fits within nvarchar, is to cast the column during replace. Borrowing the code from the accepted answer:
UPDATE YourTable
SET Column1 = REPLACE(cast(Column1 as nvarchar(max)),'a','b')
WHERE Column1 LIKE '%a%'
This worked perfectly for me. Thanks to this forum post I found for the fix. Hopefully this helps someone else!
The following will find and replace a string in every database (excluding system databases) on every table on the instance you are connected to:
Simply change 'Search String' to whatever you seek and 'Replace String' with whatever you want to replace it with.
--Getting all the databases and making a cursor
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb') -- exclude these databases
DECLARE #databaseName nvarchar(1000)
--opening the cursor to move over the databases in this instance
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #databaseName
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #databaseName
--Setting up temp table for the results of our search
DECLARE #Results TABLE(TableName nvarchar(370), RealColumnName nvarchar(370), ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #SearchStr nvarchar(100), #ReplaceStr nvarchar(100), #SearchStr2 nvarchar(110)
SET #SearchStr = 'Search String'
SET #ReplaceStr = 'Replace String'
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128)
SET #TableName = ''
--Looping over all the tables in the database
WHILE #TableName IS NOT NULL
BEGIN
DECLARE #SQL nvarchar(2000)
SET #ColumnName = ''
DECLARE #result NVARCHAR(256)
SET #SQL = 'USE ' + #databaseName + '
SELECT #result = MIN(QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME))
FROM [' + #databaseName + '].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = ''BASE TABLE'' AND TABLE_CATALOG = ''' + #databaseName + '''
AND QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME) > ''' + #TableName + '''
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME)
), ''IsMSShipped''
) = 0'
EXEC master..sp_executesql #SQL, N'#result nvarchar(256) out', #result out
SET #TableName = #result
PRINT #TableName
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
DECLARE #ColumnResult NVARCHAR(256)
SET #SQL = '
SELECT #ColumnResult = MIN(QUOTENAME(COLUMN_NAME))
FROM [' + #databaseName + '].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''[' + #databaseName + '].' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''[' + #databaseName + '].' + #TableName + ''', 1)
AND DATA_TYPE IN (''char'', ''varchar'', ''nchar'', ''nvarchar'')
AND TABLE_CATALOG = ''' + #databaseName + '''
AND QUOTENAME(COLUMN_NAME) > ''' + #ColumnName + ''''
PRINT #SQL
EXEC master..sp_executesql #SQL, N'#ColumnResult nvarchar(256) out', #ColumnResult out
SET #ColumnName = #ColumnResult
PRINT #ColumnName
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'USE ' + #databaseName + '
SELECT ''' + #TableName + ''',''' + #ColumnName + ''',''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
--Declaring another temporary table
DECLARE #time_to_update TABLE(TableName nvarchar(370), RealColumnName nvarchar(370))
INSERT INTO #time_to_update
SELECT TableName, RealColumnName FROM #Results GROUP BY TableName, RealColumnName
DECLARE #MyCursor CURSOR;
BEGIN
DECLARE #t nvarchar(370)
DECLARE #c nvarchar(370)
--Looping over the search results
SET #MyCursor = CURSOR FOR
SELECT TableName, RealColumnName FROM #time_to_update GROUP BY TableName, RealColumnName
--Getting my variables from the first item
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #t, #c
WHILE ##FETCH_STATUS = 0
BEGIN
-- Updating the old values with the new value
DECLARE #sqlCommand varchar(1000)
SET #sqlCommand = '
USE ' + #databaseName + '
UPDATE [' + #databaseName + '].' + #t + ' SET ' + #c + ' = REPLACE(' + #c + ', ''' + #SearchStr + ''', ''' + #ReplaceStr + ''')
WHERE ' + #c + ' LIKE ''' + #SearchStr2 + ''''
PRINT #sqlCommand
BEGIN TRY
EXEC (#sqlCommand)
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH
--Getting next row values
FETCH NEXT FROM #MyCursor
INTO #t, #c
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
DELETE FROM #time_to_update
DELETE FROM #Results
FETCH NEXT FROM db_cursor INTO #databaseName
END
CLOSE db_cursor
DEALLOCATE db_cursor
Note: this isn't ideal, nor is it optimized
If you are working with SQL Server 2005 or later there is also a CLR library available at http://www.sqlsharp.com/ that provides .NET implementations of string and RegEx functions which, depending on your volume and type of data may be easier to use and in some cases the .NET string manipulation functions can be more efficient than T-SQL ones.