1

I am trying to figure out how to use sp_msforeachtable to perform an action on all tables and variables that match variable/table names stored in another table

IE

I have a table that has 3 columns : table, variable, action

and I am trying to use sp_MSforeachtable to see which tables and variables match, and if match, perform that action on the table.

  1. How do you call variable names in the sp_MSforeachtable statement? I know to use ? for the table name, but not sure how I would say if variable name=variable name then do X

  2. Is there another way to do this without using this undocumented SP?

Ill try to explain better:

I am trying to clean personal info from a bunch of tables... I have a table that looks like this (not sure how to format a table, so imagine each entry is a seperate row, so the first row is Name, A, and set to '')

Variable
Name
Phone Number
Name

Table
A
A
B

Action
Set to ''
Set to '555-555-5555'
Set to ''

etc.

I then have a database full of tables....on table A, I would want my code to set all rows of variable 'Name'
to '' (blank)
, and Phone Number to '555-555-5555'
etc.and then move on to table B and do the same and so on

Arulkumar
  • 12,966
  • 14
  • 47
  • 68
Adam Sanders
  • 125
  • 11
  • 1
    It is highly likely you could do this another way. However, we have no idea what you are trying to do because the question is incredibly vague. – Sean Lange Jan 27 '16 at 17:06
  • tried to add some clarification on what I am doing...though not sure why the formatting on my attempt at a table looks so bad – Adam Sanders Jan 27 '16 at 17:16
  • There was enough detail in your original version. I think it would have been better to include code defining the table and another code block with an example of what you are trying to do. – Trisped Jan 27 '16 at 17:35
  • I am not sure exactly what you are looking to do, but I wrote this blog post a while back on sp_msforeachtable http://comp-phil.blogspot.com/2013/01/using-sql-servers-spmsforeachtable.html You might be able to find a solution in it. – Mike Harris Jan 28 '16 at 00:44

1 Answers1

0

I would use a cursor and dynamic SQL:

--Set up for test:
CREATE TABLE #DataTable (column1 nvarchar(128) NOT NULL, column2 int NOT NULL);     --Create global temp table so it can be accessed from dynamic SQL.
CREATE TABLE ##ActionTable ([table] nvarchar(128) NOT NULL, variable nvarchar(MAX) NOT NULL, [action] nvarchar(MAX) NOT NULL);
INSERT INTO ##ActionTable ([table], variable, [action])
VALUES
    ('#DataTable', '1', 'INSERT INTO @table (column1, column2) VALUES (''@variable_1'', @variable);'),
    ('#DataTable', '2', 'INSERT INTO @table (column1, column2) VALUES (''@variable_1'', @variable);'),
    ('#DataTable', '3', 'INSERT INTO @table (column1, column2) VALUES (''@variable_1'', @variable);'),
    ('#DataTable', '4', 'INSERT INTO @table (column1, column2) VALUES (''@variable_1'', @variable);');

--Code:
DECLARE @action nvarchar(MAX);
DECLARE @table nvarchar(128);
DECLARE @variable nvarchar(MAX);

DECLARE rowCurser CURSOR FOR SELECT [table], variable, [action] FROM ##ActionTable;
OPEN rowCurser;
FETCH rowCurser INTO @table, @variable, @action

WHILE @@FETCH_STATUS = 0
BEGIN
    --Execute the code (pick one of the two.  Option 2 is safer and can be cached (faster), but it does not work with my example because the parameters are left as variables).
    --  Option 1:
    SET @action = REPLACE(REPLACE(@action, '@table', @Table), '@variable', @variable);
    EXECUTE(@action);
    --  Option 2:
    EXECUTE sp_executesql @stmt = N'INSERT INTO #DataTable (column1, column2) VALUES (CAST(@variable as nvarchar(128)) + N''_2'', @variable);', @params = N'@variable nvarchar(MAX)', @variable = @variable;

    --Setup for next iteration
    FETCH rowCurser INTO @table, @variable, @action
END
CLOSE rowCurser;
DEALLOCATE rowCurser;

--Check and cleanup from test
SELECT * FROM #DataTable;
DROP TABLE #DataTable;
DROP TABLE ##ActionTable;

Note: There are security concerns with what you are trying to do, since anyone who can add to your table will have the same access as the account which runs the script. You could reduce these concerns by defining the actions in another table which can only be edited by the administrator, then referencing the action in your existing table.

Note: It is best to have the data types of @action, @table, and @variable match their source columns. The variables an be any data type in your database (as long as it is not a local temp type). You will notice that there are two places in the code above where the types are defined, first where the variables are declared at the top, and second where the arguments for sp_executesql are defined in the string near the bottom.

Note: if @stmt and @params are assigned with a constant instead of a variable, make sure to prefix the constant with N so it will be read as a Unicode string.

Trisped
  • 5,705
  • 2
  • 45
  • 58
  • Thank you for the help...one problem I am running into and I am not sure where it is coming from in this statmeent is Procedure expects parameter '@params' of type 'ntext/nchar/nvarchar'. since the declared variables are nvarchar – Adam Sanders Jan 27 '16 at 23:49
  • Sorry, change the type of `@table` in the script from `sysname` to `nvarchar(128)`. I will update the code. – Trisped Jan 27 '16 at 23:56
  • I was trying that and still seemed to get the error, so I thought maybe it was from somewhere else, but Ill try again, thanks! – Adam Sanders Jan 28 '16 at 00:04
  • I updated the code. You are probably changing the variable declaration at the top, but not the string argument which defines `'@table sysname,` near the bottom. If you still need help leave a comment and I will start a chat. – Trisped Jan 28 '16 at 00:07
  • So i created a test table to use as the actiontable: `create table ##test3 ( actionname nvarchar(max) , tablename nvarchar(128), variablename nvarchar(max) ) insert into ##test3 values ('set = ''''', 'dbo.ReplicationObject', 'Target' )` – Adam Sanders Jan 28 '16 at 00:28
  • and then `DECLARE @action nvarchar(MAX); DECLARE @table nvarchar(128); DECLARE @variable nvarchar(MAX); DECLARE rowCurser CURSOR FOR SELECT [tablename], variablename, [actionname] FROM ##test3; OPEN rowCurser; FETCH rowCurser INTO @table, @variable, @action WHILE @@FETCH_STATUS = 0 BEGIN EXECUTE sp_executesql @action, '@table nvarchar(128), @variable nvarchar(MAX)', @table = @table, @variable = @variable; FETCH rowCurser INTO @table, @variable, @action END CLOSE rowCurser; DEALLOCATE rowCurser;` and I am still getting the error... – Adam Sanders Jan 28 '16 at 00:29
  • It was the _'@table nvarchar(128), @variable nvarchar(MAX)'_. If you prefix it with an N it will work. I ran into a problem with `sp_executesql` in my example, so I switched to `EXECUTE` for my tests, but you can pick which works best for you. From your description I think you will want to change `##test3` to work with `sp_executesql`. – Trisped Jan 28 '16 at 00:58
  • @AdamSanders If this solved your issue, please accept it. If you have any questions, see https://stackoverflow.com/help/someone-answers. – Trisped Jan 29 '16 at 21:31