Update specific column in all tables base on specific value - sql

I'm trying to update all table based on my value. This is a script Task in my SSIS package.
But I get the error:
Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.
Code looks like this:
DECLARE #Column_name varchar(MAX)
DECLARE #Column_Datatype varchar(max)
SET #COLUMN_NAME='site_id'
SET #COLUMN_DATATYPE='varchar(10)'
------------------------------------------------Code---------------------------------------------------
GO
--Declare Variables
DECLARE #TableName VARCHAR(100)
DECLARE #TableSchema VARCHAR(100)
DECLARE #COLUMN_NAME VARCHAR(50)
DECLARE #COLUMN_NAME_UPDATE VARCHAR(50)
SET #COLUMN_NAME_UPDATE = ?
SET #COLUMN_NAME='site_id'
DECLARE #COLUMN_DATATYPE VARCHAR(50)
SET #COLUMN_DATATYPE='varchar(max)'
--Declare Cursor
DECLARE CUR CURSOR FOR
SELECT TABLE_SCHEMA,
TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
--OPEN CURSOR
OPEN CUR
--Fetch First Row
FETCH NEXT FROM CUR INTO #TableSchema,#TableName
--Loop
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(MAX)
SET #SQL= ( SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=#TableName AND COLUMN_NAME=#COLUMN_NAME
and Table_Schema=#TableSchema)
BEGIN
SET #SQL='UPDATE '+ #TableSchema+'.'+ '[' + #TableName + ']' + ' SET '+#COLUMN_NAME + '='
+ '''' + #COLUMN_NAME_UPDATE + '''' + 'WHERE site_id IS NULL '
PRINT #SQL
EXEC ( #SQL)
END
FETCH NEXT FROM CUR INTO #TableSchema,#TableName
END
--Close and Deallocate Cursor
CLOSE CUR
DEALLOCATE CUR
I use a variable like input.
What's wrong?

Related

Only fetching first value in column

CREATE PROC [dbo].[usp_InsertGenerator]
AS
BEGIN
DECLARE #tablename varchar(max)
DECLARE cursCol1 CURSOR FOR
SELECT name FROM sys.tables
OPEN cursCol1
FETCH NEXT FROM cursCol1 INTO #tablename
DECLARE cursCol CURSOR FOR
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = #tableName
OPEN cursCol
DECLARE #string nvarchar(3000)
DECLARE #stringData nvarchar(3000)
DECLARE #dataType nvarchar(1000)
SET #string='INSERT '+#tableName+'('
SET #stringData=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #colName,#dataType
IF ##fetch_status<>0
BEGIN
PRINT 'Table '+#tableName+' not found, processing skipped.'
--FETCH NEXT FROM cursCol1 INTO #tablename
CLOSE curscol
DEALLOCATE curscol
RETURN
END
WHILE ##FETCH_STATUS=0
--FETCH NEXT FROM cursCol1 INTO #tablename
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
SET #stringData=#stringData+'''''''''+
isnull('+#colName+','''')+'''''',''+'
END
ELSE
BEGIN
SET #stringData=#stringData+'''''''''+
isnull(cast('+#colName+' as varchar(200)),''0'')+'''''',''+'
END
SET #string=#string+#colName+','
FETCH NEXT FROM cursCol INTO #colName ,#dataType
END
BEGIN
DECLARE #Query nvarchar(4000)
SET #query ='SELECT '''+substring(#string,0,len(#string)) + ')
VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')''
FROM '+#tableName
PRINT (#query)
CLOSE cursCol1
DEALLOCATE cursCol1
CLOSE cursCol
DEALLOCATE cursCol
END
END
GO
When executing the procedure I am only getting first value(Row) from name column in sys.tables.
I want it for all the rows in the sys.tables.
Query should take each table name one by one then execute the query for every table so that I can get insert statement for all the tables.
Thanks in advance .
Please try using cursor to get name, cursCol1 Should be closed at last after cursCol. FETCH NEXT is also missing for cursCol1
CREATE PROC [dbo].[usp_InsertGenerator]
AS
BEGIN
DECLARE #tablename varchar(max)
DECLARE #tbl table (insertVal varchar(max))
DECLARE cursCol1 CURSOR FOR
SELECT name FROM sys.tables
OPEN cursCol1
FETCH NEXT FROM cursCol1 INTO #tablename
WHILE ##FETCH_STATUS=0
begin
DECLARE cursCol CURSOR FOR
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = #tableName
OPEN cursCol
DECLARE #string nvarchar(3000)
DECLARE #stringData nvarchar(3000)
DECLARE #dataType nvarchar(1000)
SET #string='INSERT '+#tableName+'('
SET #stringData=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #colName,#dataType
IF ##fetch_status<>0
BEGIN
PRINT 'Table '+#tableName+' not found, processing skipped.'
FETCH NEXT FROM cursCol1 INTO #tablename
CLOSE curscol
DEALLOCATE curscol
RETURN
END
WHILE ##FETCH_STATUS=0
--FETCH NEXT FROM cursCol1 INTO #tablename
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
SET #stringData=#stringData+'''''''''+
isnull('+#colName+','''')+'''''',''+'
END
ELSE
BEGIN
SET #stringData=#stringData+'''''''''+
isnull(cast('+#colName+' as varchar(200)),''0'')+'''''',''+'
END
SET #string=#string+#colName+','
FETCH NEXT FROM cursCol INTO #colName ,#dataType
END
BEGIN
DECLARE #Query nvarchar(4000)
SET #query ='SELECT '''+substring(#string,0,len(#string)) + ')
VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')''
FROM '+#tableName
INSERT INTO #tbl (insertVal) EXEC (#query)
-- PRINT (#query)
END
CLOSE cursCol
DEALLOCATE cursCol
FETCH NEXT FROM cursCol1 INTO #tablename
END
CLOSE cursCol1
DEALLOCATE cursCol1
SELECT * FROM #tbl
END

Need to declare a cursor with a variable in the declaration

I had a problem with a maintenance procedure and need to create a second one where I declare a cursor with a list of database ID and pass them into another cursor to get a list of tables for each database.
Current problem is that in the inner cursor even though it runs use [database_name], when i declare it and specify my query it selects the tables from the master database. it doesn't change the database context before going into the inner cursor.
DECLARE #db varchar(128)
declare #cmd varchar(1024)
declare #table varchar(255)
declare #cmd2 varchar(1024)
DECLARE crDB CURSOR global FORWARD_only FOR
SELECT [name] FROM sys.databases WHERE database_id > 4
and database_id in (33) ORDER BY [name]
OPEN crDB
FETCH crDB INTO #db
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'USE [' + #db +']'
EXEC (#cmd)
DECLARE crTB CURSOR LOCAL FAST_FORWARD FOR
select [name] from sys.objects where type = 'u' ORDER BY [name]
OPEN crTB
FETCH crTB INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd2 = 'Update Statistics ' + #table + CHAR(13)
PRINT #cmd2
EXEC (#cmd2)
end
CLOSE crTB
DEALLOCATE crTB
FETCH crDB INTO #db
END
CLOSE crDB
DEALLOCATE crDB
GO
The issue with your inner cursor, is scope. You can to do 2 things here. You have to move your inner cursor to right after the USE [' + #db like:
DECLARE #db VARCHAR(128);
DECLARE #cmd VARCHAR(1024);
DECLARE #table VARCHAR(255);
DECLARE #cmd2 VARCHAR(1024);
DECLARE crDB CURSOR GLOBAL READ_ONLY FORWARD_ONLY FOR
SELECT name
FROM sys.databases
WHERE database_id > 4
AND database_id IN (33)
ORDER BY name;
OPEN crDB;
FETCH crDB
INTO #db;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'USE [' + #db + ']
GO;
DECLARE crTB CURSOR LOCAL FAST_FORWARD FOR
SELECT name
FROM sys.objects
WHERE type = ''u'';
ORDER BY name;
OPEN crTB;
FETCH NEXT FROM crTB
INTO #table;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd2 = ''Update Statistics '' + #table + CHAR(13);
PRINT #cmd2;
EXEC (#cmd2);
END;
CLOSE crTB;
DEALLOCATE crTB;
';
EXEC (#cmd);
FETCH NEXT FROM crDB
INTO #db;
END;
CLOSE crDB;
DEALLOCATE crDB;
Or you can get rid of the inner cursor altogether and use sys.sp_MSforeachtable:
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'USE [' + #db + ']
GO;
EXEC sys.sp_MSforeachtable #command1 = ''UPDATE STATISTICS ?;''';
EXEC (#cmd);

Iterate through all tables

I'm looking for a way to iterate through all tables in a database.
I've come up with this so far:
DECLARE #TableName VARCHAR(MAX)
DECLARE MyCursor CURSOR
FOR
SELECT
DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG ='MyDB'
AND TABLE_SCHEMA=N'dbo'
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT *
FROM #TableName
FETCH NEXT FROM MyCursor INTO #TableName
END
CLOSE MyCursor
DEALLOCATE MyCursor
I get an error message in the While statement The #TableName tablevariable must be declared (translated from German).
I know there should be a variable of the type TABLE at FROM #TableName, but I haven't found how to do that, just how to declare new tables which I don't want.
You can't SELECT * FROM #TableName
you will need to use Dynamic SQL
declare #sql nvarchar(max)
SELECT #sql = 'SELECT * FROM ' + QUOTENAME(#TableName)
exec sp_executesql #sql
In order to execute select on all your tables, you have to use dynamic SQL, as mentioned in other answer. Additionally, you don't need cursor at all! :)
Try this:
declare #sql varchar(max) = '';
select #sql = #sql + 'select * from ' + TABLE_CATALOG + '.' + TABLE_SCHEMA + '.' + TABLE_NAME + ' '
from information_schema.tables
exec(#sql)

Copy NAV Database Structure to another Database along with Data in SQL

I need to Copy a Company in NAV Database to another Company in Different Database with SQL Query. I have achived this using the code below, but if the Structure is different in the Source or Destination my code fails. Please help me in modifying it, so i can copy the Structure and Data from the Source and replace Data and Structure in the Destination.
The code is given below.
-- =============================================
-- Author: Prajeesh
-- Create date: 31.03.2015
-- Description: Function for copying comany from one database to another
-- =============================================
Create PROCEDURE [dbo].[sp_NAVCopyCompany_v2]
#sourcecompany varchar(max),
#targetdb varchar(max),
#targetcompany varchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
declare #tablename varchar(1000)
declare #columns varchar(max)
declare #columnname varchar (max)
declare #targettable varchar (max)
declare #isidentity int
declare #sqlcommand nvarchar (max) = 'select name from '+#targetdb+'.sys.all_objects where type=''U'' and object_id>0 and name like '''+#sourcecompany+'$%'''
declare #sqlcommandIdentity nvarchar (max)
declare #tablevar table(name varchar(300))
declare #columntablevar table(COLUMN_NAME varchar(300))
declare #identitytablevar table(C int)
insert into #tablevar(name) exec sp_executesql #sqlcommand
DECLARE table_cursor CURSOR for
select name from #tablevar
OPEN table_cursor
FETCH NEXT FROM table_cursor
INTO #tablename
WHILE ##FETCH_STATUS = 0
BEGIN
--RAISERROR (#tablename, 0, 1) WITH NOWAIT
set #sqlcommand = 'SELECT COLUMN_NAME FROM '+#targetdb+'.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '''+#tablename+''' and COLUMN_NAME <> ''timestamp'''
DELETE from #columntablevar
insert into #columntablevar(COLUMN_NAME) exec sp_executesql #sqlcommand
DECLARE column_cursor CURSOR for select COLUMN_NAME from #columntablevar
select #columns=''
OPEN column_cursor
FETCH NEXT from column_cursor
INTO #columnname
WHILE ##FETCH_STATUS=0
BEGIN
SELECT #columns=#columns+',['+#columnname+']'
FETCH NEXT from column_cursor
INTO #columnname
END
CLOSE column_cursor;
DEALLOCATE column_cursor;
select #columns = SUBSTRING(#columns,2,LEN(#columns)-1)
--RAISERROR (#columns, 0, 1) WITH NOWAIT
select #targettable= #targetdb+'.dbo.['+#targetcompany+SUBSTRING(#tablename,LEN(#sourcecompany)+1,LEN(#tablename)-LEN(#sourcecompany)+1)+']'
--
select #isidentity=COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =#tablename AND COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
--
set #sqlcommandIdentity = 'SELECT COUNT(*) as C FROM '+#targetdb+'.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='''+#tablename+''' AND COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, ''IsIdentity'') = 1'
DELETE from #identitytablevar
insert into #identitytablevar(C) exec sp_executesql #sqlcommandIdentity
select #isidentity=SUM(C) FROM #identitytablevar
RAISERROR (#targettable, 0, 1) WITH NOWAIT
set #sqlcommand = ''
IF (#isidentity>0)
set #sqlcommand = #sqlcommand + 'SET IDENTITY_INSERT '+#targettable+' ON;'
set #sqlcommand = #sqlcommand + 'delete from '+#targettable+';'
set #sqlcommand = #sqlcommand + 'insert into '+#targettable+ ' ('+ #columns + ')'
+ ' select '+#columns
+ ' from ['+#tablename+']'
IF (#isidentity>0)
set #sqlcommand = #sqlcommand + ';SET IDENTITY_INSERT '+#targettable+' OFF'
--RAISERROR (#sqlcommand, 0, 1) WITH NOWAIT
exec sp_executesql #sqlcommand
FETCH NEXT FROM table_cursor
INTO #tablename
END
CLOSE table_cursor;
DEALLOCATE table_cursor;
END
The Query is called as
use SourceDatabase
exec sp_NAVCopyCompany_v2 'Source Company_','Destination Database','Destination Company'

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.