5

I'm trying to execute the same sequence of actions on a list of tables, which are selected using a where clause.

Select table_name 
From INFORMATION_SCHEMA.COLUMNS 
Where column_name = 'fieldA';

This generates a list of table names - these are the tables I want to handle with a for loop. Is there a way to iterate through this list of tables, something like this?

for i in @tablelist:

    alter table i add new_col varchar(8);
    update i set new_col = old_col;
5
  • Hmm... dunno if you can run DDL in a DML query... in fact, I'm pretty sure you can't. Commented Oct 26, 2017 at 17:31
  • You have to use dynamic sql Commented Oct 26, 2017 at 18:03
  • Why are you adding a new column and setting the value to be the same as another column? This seems kind of silly to have two columns with the same data in them. Perhaps you then are going to drop the old column? Maybe simply renaming these columns would be an option. Commented Oct 26, 2017 at 18:23
  • I'm doing other stuff to the new column, removing characters to change the formatting. Didn't think it relevant to the scope of the question. Commented Oct 26, 2017 at 18:31
  • Gotcha. If you are doing other stuff that makes total sense. As posted it seemed like simple renaming might have been a better path. Seems it isn't quite that simple. :) Commented Oct 26, 2017 at 18:33

4 Answers 4

9

You could try this:

DECLARE @Table TABLE
(
TableName VARCHAR(50),
Id int identity(1,1)
)


INSERT INTO @Table
Select table_name From INFORMATION_SCHEMA.COLUMNS 
Where column_name = 'fieldA'

DECLARE @max int
DECLARE @SQL VARCHAR(MAX) 
DECLARE @TableName VARCHAR(50)
DECLARE @id int = 1

select @max = MAX(Id) from @Table


WHILE (@id <= @max)
BEGIN

SELECT @TableName = TableName FROM @Table WHERE Id = @id
SET @SQL =     'alter table '+ @TableName +' add new_col varchar(8);
                update '+ @TableName + ' set new_col = old_col;'
PRINT(@SQL)  --COMMENT THIS LINE OUT AND COMMENT IN THE NEXT EXEC(@SQL) IF YOU SEE THE CORRECT OUTPUT
--EXEC(@SQL)
SET @id = @id +1
END
Sign up to request clarification or add additional context in comments.

Comments

6

You do not need to use loops for this. You can use the system view to generate your dynamic sql for you a lot simpler (and faster) than loops.

declare @SQL nvarchar(max) = ''

select @SQL = @SQL + 'alter table ['+ c.TABLE_NAME +'] add new_col varchar(8);
                update ['+ c.TABLE_NAME + '] set new_col = old_col;'
from INFORMATION_SCHEMA.COLUMNS c
where c.COLUMN_NAME = 'fieldA'

select @SQL
--uncomment below when you are satisfied with the dynamic sql
--exec sp_executesql @SQL

8 Comments

In the last step write EXEC(@SQL)
@BartoszSiemasz NO. using sp_executesql is a better choice. In this case it doesn't much matter but EXEC does not allow parameters where sp_executesql does. sqlblog.org/2011/09/17/…
Ok, sp_executesql delivers additional value for the future amendments, right.
I'm getting the error The data types nvarchar(max) and varchar are incompatible in the subtract operator. The old_col and fieldA fields are always varchar(10) in each table. Tried changing declare @SQL varchar(max) = '' but same error.
apologies, it's because I'm doing a string operation which I left out of the original question!
|
2

For looping you either have to use cursors or while exists construct, where you remove entry from temporary table each time you process it.

As for passing table name to query, there is no way to do that without creating dynamic SQL query. You do that by creating query in string with concatenating table name into the right place. Use QUOTENAME function to perform quoting of name if there are any spaces or weird characters.

Example with cursor:

DECLARE @tables TABLE (
    Name SYSNAME
);
DECLARE @tableName SYSNAME;
DECLARE @sql NVARCHAR(4000);

INSERT INTO @tables
SELECT i.table_name
FROM INFORMATION_SCHEMA.COLUMNS i
WHERE i.column_name = 'fieldA';

DECLARE cur CURSOR LOCAL FAST_FORWARD
FOR
SELECT Name
FROM @tables;

OPEN cur;

FETCH NEXT FROM cur
INTO @tableName;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = N'ALTER TABLE ' + QUOTENAME(@tableName) + N' ADD new_col varchar(8);';
    SET @sql = @sql + N'UPDATE ' + QUOTENAME(@tableName) + N' SET new_col = old_col;';

    EXEC sp_executesql @sql;

    FETCH NEXT FROM cur
    INTO @tableName;    
END

CLOSE cur;
DEALLOCATE cur;

Comments

1

One way to accomplish this action would be to feed your list of tables you want to alter into a SQL cursor and iterate through the cursor to execute the ALTER table command on each table. The documentation on how to create a SQL cursor can be found here: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/declare-cursor-transact-sql

Another way to accomplish this would be using a while loop in SQL with a count iterator. Information on this solution can be found here: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/while-transact-sql

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.