Copy NAV Database Structure to another Database along with Data in SQL - 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'

Related

Update specific column in all tables base on specific value

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?

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);

SQL -Query to find specific column in all the tables of the database but having no null values

I am not an SQL Expertise. I need to search for the column which is present in all the tables of the database but which does not has null values stored for that specific record.
Below is the query that fetches me all the tables that has my column name:
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE column_name LIKE 'classPK'
Try this...
declare #q nvarchar(1000);
declare cur_Select cursor for
select 'select * from ['+tab.name+'] where ['+col.name+'] is not null'
from sys.tables tab
join sys.columns col
on tab.object_id = col.object_id
where col.name like 'name'
open cur_Select
fetch next from cur_Select into #q
while ##FETCH_STATUS = 0
begin
exec sp_executesql #q
fetch next from cur_Select into #q
end
close cur_Select
deallocate cur_Select
Try with this statement:
DECLARE #TABLE_NAME NVARCHAR(MAX);
DECLARE #COLUMN_NAME NVARCHAR(MAX);
DECLARE #crs CURSOR;
DECLARE #query NVARCHAR(MAX);
set #crs = CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE column_name LIKE 'CD_CIC_PROD%'
BEGIN TRY
OPEN #crs
END TRY
BEGIN CATCH
END CATCH
FETCH NEXT FROM #crs INTO
#TABLE_NAME, #COLUMN_NAME
WHILE (##FETCH_STATUS = 0)
BEGIN
set #query = 'SELECT * FROM ['+#TABLE_NAME+'] WHERE ['+#COLUMN_NAME+'] IS NOT NULL'
EXEC sp_executesql #query
FETCH NEXT FROM #crs INTO
#TABLE_NAME, #COLUMN_NAME
END

Using cursor within UDF, returns a column which has name of different table

Create FUNCTION [dbo].[fn_GetStockDeatils]()
RETURNS #Results TABLE
(
PurchaseData nvarchar(50) NOT NULL
)
AS
BEGIN
Declare #tableName varchar(25)
Declare #PKKey numeric(18,0)
DECLARE StockCursor CURSOR FOR Select tableName ,PKKey from INVM
OPEN StockCursor
FETCH StockCursor INTO #tableName ,#PKKey
Begin
Insert #Results Select PurchaseData from #tableName.PKKey =#PKKey
END
FETCH StockCursor INTO #tableName ,#PKKey
close StockCursor
DEALLOCATE StockCursor
Return
END
I have already written this but it does not working properly. #tableName contains the name of the table. Please help me if possible.
Sounds like you need an dynamic SQL commands, but you cannot use dynamic SQL from a function. For that you have to create stored procedure.
CREATE PROCEDURE [dbo].[GetStockDeatils]
AS
BEGIN
DECLARE #tableName varchar(25),
#PKKey numeric(18,0),
#dsql nvarchar(max) = N''
IF OBJECT_ID('tempdb.dbo.#Results') IS NOT NULL DROP TABLE dbo.#Results
CREATE TABLE dbo.#Results(PurchaseData nvarchar(50) NOT NULL)
DECLARE StockCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT tableName ,PKKey
FROM INVM
OPEN StockCursor
FETCH NEXT FROM StockCursor INTO #tableName, #PKKey
WHILE ##FETCH_STATUS = 0
BEGIN
SET #dsql = 'Insert dbo.#Results Select PurchaseData from ' + #tableName + ' WHERE PKKey = ' + CAST(#PKKey AS varchar(10))
EXEC sp_executesql #dsql
FETCH NEXT FROM StockCursor INTO #tableName, #PKKey
END
CLOSE StockCursor
DEALLOCATE StockCursor
SELECT *
FROM dbo.#Results
END
EXEC [dbo].[GetStockDeatils]
Demo on SQLFiddle
Procedure creating view
CREATE PROCEDURE [dbo].[GetStockDeatils]
AS
BEGIN
DECLARE #dsql nvarchar(max) = N''
IF OBJECT_ID('dbo.v_Results') IS NOT NULL DROP VIEW dbo.v_Results
SELECT #dsql +=
'UNION ALL SELECT PurchaseData FROM ' + tableName +
' WHERE PKKey = ' + CAST(PKKey AS varchar(10))
FROM dbo.INVM
SET #dsql = N'CREATE VIEW dbo.v_Results AS ' + STUFF(#dsql, 1, 10, '')
EXEC sp_executesql #dsql
END
EXEC [dbo].[GetStockDeatils]
SELECT *
FROM dbo.v_Results