Sql Cursor....not adding data into the temporary created table - sql

I have the below cursor. It generates the right set of statements but I am not able to insert the data into the temporary created table. The cursor is as below. Please have a look.
--use a cursor to get the stats
use qcsiteadmin_db0
-- Declare the variables needed
DECLARE #DOMAIN_NAME VARCHAR(255)
DECLARE #PROJECT_NAME VARCHAR(255)
DECLARE #DB_NAME VARCHAR(60)
DECLARE #SQL NVARCHAR(max)
DECLARE #COUNTSQL NVARCHAR(2000)
DECLARE #FOLDER VARCHAR(255)
---DECLARE #FILTER VARCHAR(500)
select #FOLDER = 'System Validation'
-- Create a Temp Table
CREATE TABLE #defects(
DOMAIN_NAME VARCHAR(255),
PROJECT_NAME varchar(255),
DEFECT_NUMBER int,
SUMMARY VARCHAR(255),
ASSIGNED_TO VARCHAR(255),
DESCRIPTION VARCHAR(8000),
STATUS VARCHAR(255),
PRIORITY int)
--Declare the Cursor for looping the database calls
DECLARE qc_dbs CURSOR FOR
select DOMAIN_NAME,PROJECT_NAME,DB_NAME
from td.PROJECTS
where PR_IS_ACTIVE = 'Y'
and DOMAIN_NAME not in
('mk_conversion', 'default','other','z_archivedprojects','sqa')
order by DOMAIN_NAME,PROJECT_NAME
--For each valid QC database get the defect counts needed
OPEN qc_dbs
FETCH NEXT FROM qc_dbs INTO #DOMAIN_NAME,#PROJECT_NAME,#DB_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
select #SQL = 'select ''' + #DOMAIN_NAME + ''', ''' + #PROJECT_NAME + ''', ' + #DB_NAME + '.td.bug.BG_BUG_ID, ' + #DB_NAME + '.td.bug.BG_SUMMARY, ' + #DB_NAME + '.td.bug.BG_RESPONSIBLE,
' + #DB_NAME + '.td.bug.BG_PRIORITY
from ' + #DB_NAME + '.td.CYCL_FOLD ' +
' INNER JOIN ' + #DB_NAME + '.td.bug on '
+ #DB_NAME + '.td.CYCL_FOLD.CF_ASSIGN_RCYC = ' + #DB_NAME + '.td.BUG.BG_DETECTED_IN_RCYC
and ' + #DB_NAME + '.td.CYCL_FOLD.CF_ITEM_NAME = ''' + #FOLDER + ''' and ' + #DB_NAME + '.td.BUG.BG_STATUS = ''New'' '
print #SQL
BEGIN TRY
insert into #defects
execute (#SQL)
END TRY
BEGIN CATCH
print 'Error accessing' + #DOMAIN_NAME + '.' + #PROJECT_NAME
END CATCH;
FETCH NEXT FROM qc_dbs INTO #DOMAIN_NAME,#PROJECT_NAME,#DB_NAME
END
-- Close the Cursor
CLOSE qc_dbs
DEALLOCATE qc_dbs
--Select from Temp Table
select
DOMAIN_NAME,PROJECT_NAME,
DEFECT_NUMBER,SUMMARY,ASSIGNED_TO,DESCRIPTION,
STATUS, PRIORITY
from #defects
-- Destroy the Temp Table
Drop TABLE #defects
My output messsages look like -
select 'ADMIN_SYSTEMS', '1099Process', admin_systems_1099process_db.td.bug.BG_BUG_ID, admin_systems_1099process_db.td.bug.BG_SUMMARY, admin_systems_1099process_db.td.bug.BG_RESPONSIBLE,
admin_systems_1099process_db.td.bug.BG_PRIORITY
from admin_systems_1099process_db.td.CYCL_FOLD INNER JOIN admin_systems_1099process_db.td.bug on admin_systems_1099process_db.td.CYCL_FOLD.CF_ASSIGN_RCYC = admin_systems_1099process_db.td.BUG.BG_DETECTED_IN_RCYC
and admin_systems_1099process_db.td.CYCL_FOLD.CF_ITEM_NAME = 'System Validation' and admin_systems_1099process_db.td.BUG.BG_STATUS = 'New'
(0 row(s) affected)
Error accessingADMIN_SYSTEMS.1099Process
Please have a look.
Regards.

Related

SQL Server scope issue with Dynamic SQL

The following code is from a sproc in our ERP system:
ALTER procedure [dbo].[spGrantAFUserSelectPerm]
iLoginName varchar(255) = null,
#iAppDB varchar(255)= null,
#iPLDB varchar(255)= null,
#retcode int output
as
declare #TableName varchar(255)
declare #TableCursor varchar(255)
declare #ProcName varchar(255)
declare #ProcCursor varchar(255)
select #retcode = 1
if #iLoginName is null
return #retcode
--AppDB
if #iAppDB is not null and #iAppDB <> ''
begin
select #TableCursor = 'select name from ' + #iAppDB + '..sysobjects where (type = ''U'' OR type = ''V'' OR type = ''TF'') AND uid = 1'
exec ('declare c_GrantAppTableAccess cursor for ' + #TableCursor + ' for READ ONLY')
open c_GrantAppTableAccess
fetch c_GrantAppTableAccess into #TableName
while ##fetch_status = 0
begin
exec ('use ' + #iAppDB + ' grant SELECT on ' + #TableName + ' to [' + #iLoginName + ']')
fetch c_GrantAppTableAccess into #TableName
end
close c_GrantAppTableAccess
deallocate c_GrantAppTableAccess
end
This code was working for years up until last week, when one of our developers was trying (unsuccessfuly) to deploy a CLR sproc. Now, the sproc fails on line "open c_GrantAppTableAccess" with an error saying the cursor does not exist. It is as if the cursor declaration is out of scope. Any ideas? Again, this was working for 5-7 years before last week.

List tables with recently modified records

I have a field namely Modified_Dt of type Datetime in all of my tables, to keep track of last modified date and time for a record.
Now, let's say I need to know which tables has records that has been modified recently(like today).
How do I write a query for that? How do I query multiple tables?
By the way, I am using MS SQL Server 2008 R2.
USE MASTER
GO
DECLARE #ObjectName NVARCHAR(255)
DECLARE TablesList CURSOR
FOR select object_name(object_id, db_id('DBStackExchange'))
from [DBStackExchange].sys.columns
where name = 'Modified_Dt'
OPEN TablesList
FETCH NEXT FROM TablesList INTO #ObjectName
WHILE ##FETCH_STATUS = 0
BEGIN
exec
( 'If exists ( SELECT 1 FROM DBStackExchange.dbo.[' + #ObjectName
+ ']
Where convert(varchar(20),Modified_Dt,103)>=convert(varchar(20),getdate(),103))
Print ''' + #ObjectName + '''
'
)
FETCH NEXT FROM TablesList INTO #ObjectName
END
CLOSE TablesList
DEALLOCATE TablesList
Note: Replace 'DBStackExchange' with your Database name
declare #T table (T_Name nvarchar(255), M datetime)
declare #T_Name nvarchar(255), #SQLT nvarchar(max)
declare c cursor for select name from sys.tables
open c
fetch next from c into #T_Name
while ##fetch_status = 0 begin
set #SQLT = 'select top 1 ''' + #T_Name + ''', Modified_Dt from ' + #T_Name + ' order by Modified_Dt desc'
insert #T
exec sp_executesql #SQLT
fetch next from c into #T_Name
end
close c
deallocate c
select * from #T where M >= dateadd(day,datediff(day,0,getdate()),0)
Here is an answer without cursor or temporary table
DECLARE #ColumnName AS nvarchar(40) = 'Modified_Dt';
DECLARE #ModifiedSince AS datetime = '20140709';
DECLARE #sql AS nvarchar(max) = '';
-- Build a query with UNION ALL between all tables containing #ColumnName
WITH AllTables AS (
SELECT SCHEMA_NAME(Tables.schema_id) AS SchemaName
,Tables.name AS TableName
,Columns.name AS ColumnName
FROM sys.tables AS Tables
INNER JOIN sys.columns AS Columns
ON Tables.object_id = Columns.object_id
WHERE Columns.name = #ColumnName
)
SELECT #sql = #sql +
'UNION ALL SELECT ' + QUOTENAME(TableName, '''') +
', ' + QUOTENAME(ColumnName) +
' FROM ' + QUOTENAME(TableName) + CHAR(13)
FROM AllTables;
-- Create a query which selects last change from all tables
SET #sql =
'WITH AllChanges(TableName, ModifiedTime) AS ( ' +
STUFF(#sql, 1, LEN('UNION ALL'), '') + -- Remove first UNION
') ' +
'SELECT TableName ' +
' ,MAX(ModifiedTime) ' +
'FROM AllChanges ' +
'WHERE ModifiedTime > #ModifiedSince '
'GROUP BY TableName '
EXECUTE sp_executesql #sql, N'#ModifiedSince datetime', #ModifiedSince

Explicit value for the identity column in table error?

I get the below error message, I have debugged both identity inserts and they execute with no problems. Has anyone had trouble with this error before and does anyone know how to fix this?
Msg 8101, Level 16, State 1, Line 1
An explicit value for the identity column in table 'c365online_script1.dbo.tProperty' can only be specified when a column list is used and IDENTITY_INSERT is ON.
Code:
declare #Source_Database_Name varchar(255) = 'Production2';
declare #Destination_Database_Name varchar(255) = 'c365online_script1';
declare #Company_Id int = 1 --declare a companyid
CREATE TABLE #CompanyID (ID bigint)
INSERT INTO #CompanyID(ID)
VALUES('15')
-- Copy over company records from tCompanytable
--FIRST CURSOR LOOP THROUGH THIS TABLE
CREATE TABLE #TableList (
processorder int,
tablename NVARCHAR(100)
)
INSERT INTO #TableList (processorder, tablename )
VALUES
(1, 'tProperty');
DECLARE #Counter INT = 0 -- counting variable
----------- Cursor specific code starts here ------------
-- company cursor
declare copyCompanyDataCursor CURSOR fast_forward FOR
SELECT ID from #CompanyID;
open copyCompanyDataCursor
fetch next from copyCompanyDataCursor into #Company_Id;
WHILE ##FETCH_STATUS = 0
BEGIN
declare #processorder int;
declare #tablename varchar(500);
-- table cursor
declare copyTableDataCursor CURSOR fast_forward FOR
SELECT processorder,tablename from #TableList order by processorder;
open copyTableDataCursor
fetch next from copyTableDataCursor into #processorder, #tablename;
while ##FETCH_STATUS = 0
BEGIN
SET IDENTITY_INSERT [c365online_script1].[dbo].[tCompany] ON
-- Does the table have a companyID column? if statement checking for company id
IF EXISTS(SELECT * FROM Production2.INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='CompanyID' and TABLE_NAME=#tablename)
BEGIN
if #Counter <= 0 -- make sure loop executes only once.
BEGIN
declare #debug varchar(max)
SET #debug = 'INSERT INTO ' + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename + ' WHERE ' + #Source_Database_Name + '.dbo.' + #tablename + '.CompanyID = ' + CAST(#Company_Id as varchar(10))
print #debug
set #Counter = 1
EXEC(#debug)
--EXEC('INSERT INTO ' + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename + ' WHERE ' + #Source_Database_Name + '.dbo.' + #tablename + '.CompanyID = ' + #Company_Id )
END
END
ELSE
BEGIN
Print 'No'
END
-- if yes then copy data based on companyID in cursor
-- if no check if this is the first time through company loop and copy all data
-- if #firstloop company exists look at information schema
--EXEC('INSERT INTO ' + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename )
-- company logic
SET IDENTITY_INSERT [c365online_script1].[dbo].[tCompany] OFF
FETCH NEXT FROM copyTableDataCursor into #processorder,#tablename;
END
close copyTableDataCursor;
Deallocate copyTableDataCursor;
--INSERT INTO c365online_script1.dbo.tCompany
--SELECT *
--FROM production2.tCompany
--WHERE ISNULL(CompanyID, 0) = 0 -- copy all data where id is equal to zero
--#Destination_Database_Name
--
--EXEC(INSERT + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename + ' WHERE ' + #Source_Database_Name + '.dbo.' + #tablename + '.CompanyID = ' + #Company_Id + ')')
--SET #firstLoop = false;
FETCH NEXT FROM copyCompanyDataCursor into #Company_Id;
END
CLOSE copyCompanyDataCursor;
DEALLOCATE copyCompanyDataCursor;
--Cleanup
DROP TABLE #CompanyID
DROP TABLE #TableList
Well, the error says it all:
An explicit value for the identity column in table 'c365online_script1.dbo.tProperty' can only be specified when a column list is used and IDENTITY_INSERT is ON.
So your INSERT statement MUST use a column list!
Use
INSERT INTO dbo.Table(col1, col2, ...., colN) VALUES(Val1, val2, ...., ValN)
and not just
INSERT INTO dbo.Table VALUES(Val1, val2, ...., ValN)
^^^^ no column list defined!!
then it'll work!

Assistance with IF Statement

I need some assistance with my tsql , I have knowledge of sql but mainly just querying tables and im finding tsql and loops quite difficult to finish off.
I have hit a sticking point with my IF STATEMENT.
As you can see I have wrote the loop and attempted some debugging and the code is correct so far.
In the Else section
I need to check if it’s the first time through the loop using #firstloop and then copy all data , its mainly the loop that I’m having problems with and could do with help on getting a starting point.
I am using cursors but have been told it won’t affect performance because it’s not doing too much work and I would appreciate any help with the problem.I have also been told that some sections are Hard coded such as Production2 which should be #Source_Database_Name.
declare #Source_Database_Name varchar(255) = 'Production2';
declare #Destination_Database_Name varchar(255) = 'c365online_script1';
declare #Company_Id int = 1 --declare a companyid
CREATE TABLE #CompanyID (ID bigint)
INSERT INTO #CompanyID(ID)
VALUES('15')
--FIRST CURSOR LOOP THROUGH THIS TABLE
CREATE TABLE #TableList (
processorder int,
tablename NVARCHAR(100)
)
INSERT INTO #TableList (processorder, tablename )
VALUES
(1, 'tProperty');
DECLARE #firstLoop BIT
--SET #firstLoop = true
DECLARE #Counter INT -- counting variable
----------- Cursor specific code starts here ------------
-- company cursor
declare copyCompanyDataCursor CURSOR fast_forward FOR
SELECT ID from #CompanyID;
open copyCompanyDataCursor
fetch next from copyCompanyDataCursor into #Company_Id;
WHILE ##FETCH_STATUS = 0
BEGIN
declare #processorder int;
declare #tablename varchar(500);
-- table cursor
declare copyTableDataCursor CURSOR fast_forward FOR
SELECT processorder,tablename from #TableList order by processorder;
open copyTableDataCursor
fetch next from copyTableDataCursor into #processorder, #tablename;
while ##FETCH_STATUS = 0
BEGIN
SET IDENTITY_INSERT [c365online_script1].[dbo].[tCompany] ON
-- Does the table have a companyID column? if statement checking for company id
IF EXISTS(SELECT * FROM Production2.INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME='CompanyID' and TABLE_NAME=#tablename)
BEGIN
declare #debug varchar(max)
SET #debug = 'INSERT INTO ' + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename + ' WHERE ' + #Source_Database_Name + '.dbo.' + #tablename + '.CompanyID = ' + CAST(#Company_Id as varchar(10))
print #debug
--EXEC(#debug)
--EXEC('INSERT INTO ' + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename + ' WHERE ' + #Source_Database_Name + '.dbo.' + #tablename + '.CompanyID = ' + #Company_Id )
END
ELSE
-- if no check if this is the first time through company loop and copy all data- if #firstloop company exists look at information schema
BEGIN
Print 'No'
END
-- if yes then copy data based on companyID in cursor
--EXEC('INSERT INTO ' + #Destination_Database_Name + '.dbo.' + #tablename + ' SELECT * FROM ' + #Source_Database_Name + '.dbo.' + #tablename )
-- company logic
SET IDENTITY_INSERT [c365online_script1].[dbo].[tCompany] OFF
FETCH NEXT FROM copyTableDataCursor into #processorder,#tablename;
END
close copyTableDataCursor;
Deallocate copyTableDataCursor;
Not sure why you are using the cursor. To answer your question of "checking if its the first time gone through loop" then below is the soullution for this.
Declare a variable above "while ##FETCH_STATUS = 0" Line.
somethign like "Firsttime = 0 "
Under IF , "Firsttime = 1 " Which means this is not first time.
In ELSE , check
---> if "Firsttime = 0 " Then it mean first time
---> if "Firsttime = 1 " Then it mean its not first time

Creating A Script To Replicate A Table And Its Contents?

I know you can create a script to replicate a table using:
right click table > script table as > create to > new query editor window
But how can I generate a script that contains a bunch of insert commands for each row in the table?
Table1
Id1, Row1
Id2, Row2
Id3, Row3
Insert into Table1 values(Row1);
Insert into Table1 values(Row2);
Insert into Table1 values(Row3);
I ended up doing this
right click database > Tasks > Generate Scripts ... > selected the tables > in the advanced options I set "Types of data to script" to "Schema and data"
Select
'Insert into Table (
IntField1
StringField2
Column3)
values (' +
IntField1 + ',' +
+ '''' + StringField2 + ''',' +
Column2 + ')' as InsertQuery
From Table
Something like this, just remember if your string contains a single quote you will need to make sure you replace it like this replace(stringfield, '''', '''''')
So this isnt super pretty cuz I kind of took one of my sp's and hacked it up for this. But basically this will take any table and print a series of insert statements into a table called tbl_text (which you would need to create)
The arguments are the table name and the table ID from sysobjects
--this is how you get the tbl_id
SELECT id FROM sysobjects WHERE type = 'U' AND name = 'tablename'
CREATE PROCEDURE dbo.sp_export_table
#tblhdr varchar(100),
#tblID varchar(100)
AS
SET NOCOUNT ON
IF object_id('tempdb..##temptable') IS NOT NULL
BEGIN
DROP TABLE ##temptable
END
DECLARE #identity bit
DECLARE #typestmt nvarchar(100)
DECLARE #typeval int
DECLARE #rowstmt nvarchar(1000)
DECLARE #rowID varchar(50)
DECLARE #orderby nvarchar(100)
DECLARE #clmnstmt varchar(200)
DECLARE #clmnhdr varchar(50)
DECLARE #clmnstring varchar(1000)
DECLARE #valuestmt nvarchar(200)
DECLARE #valuestring nvarchar(3000)
DECLARE #value nvarchar(1000)
DECLARE #insertstmt varchar(1000)
DECLARE #params nvarchar(100)
DECLARE #param2 nvarchar(100)
SELECT #rowstmt = N'SELECT TOP 1 #inside_var = name FROM syscolumns WHERE id = ' + #tblID + ' ORDER BY colorder'
SELECT #params = N'#inside_var NVARCHAR(1000) OUTPUT'
EXEC sp_executesql #rowstmt, #params, #inside_var = #orderby OUTPUT
SELECT #rowstmt = 'SELECT *, ROW_NUMBER() OVER (ORDER BY ' + #orderby + ') AS row INTO ##temptable FROM ' + #tblhdr
exec(#rowstmt)
IF object_id('tempdb..##temptable') IS NOT NULL
BEGIN
DECLARE row_cursor CURSOR FOR
SELECT row FROM ##temptable
OPEN row_cursor
FETCH NEXT FROM row_cursor
INTO #rowID
--if table has identity and has records write identity_insert on
SET #identity = 0
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE OBJECTPROPERTY(OBJECT_ID(TABLE_NAME),
'TableHasIdentity') = 1 AND TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME = #tblhdr) AND EXISTS(SELECT * FROM ##temptable)
BEGIN
SET #identity = 1
INSERT INTO dbo.tbl_text VALUES('SET IDENTITY_INSERT dbo.' + #tblhdr + ' ON')
END
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #clmnstmt = 'DECLARE column_cursor CURSOR FOR SELECT name FROM syscolumns WHERE id = ' + #tblID + ' ORDER BY colorder'
exec(#clmnstmt)
OPEN column_cursor
FETCH NEXT FROM column_cursor
INTO #clmnhdr
SELECT #clmnstring = '('
SELECT #valuestring = '('
WHILE ##FETCH_STATUS = 0
BEGIN
IF #clmnhdr <> 'row'
BEGIN
SELECT #clmnstring = #clmnstring + #clmnhdr + ','
SELECT #valuestmt = N'SELECT #inside_var = ' + #clmnhdr + ' FROM ##temptable WHERE row = ' + #rowID
EXEC sp_executesql #valuestmt, #params, #inside_var = #value OUTPUT
SELECT #typestmt = N'SELECT #inside_var2 = xtype FROM syscolumns WHERE name = ''' + #clmnhdr + ''' AND id = ' + #tblID
SELECT #param2 = N'#inside_var2 INT OUTPUT'
EXEC sp_executesql #typestmt, #param2, #inside_var2 = #typeval OUTPUT
IF #typeval NOT IN (48,52,56,59,60,62,104,108,122,127)
BEGIN
SET #value = REPLACE(#value,'''','''''')
SET #value = '''' + #value + ''''
SET #value = ISNULL(#value, '''''')
END
IF NOT (#typeval = 34)
BEGIN
SELECT #valuestring = #valuestring + #value + ','
END
ELSE
BEGIN
SELECT #valuestring = #valuestring + '''''' + ','
END
END
FETCH NEXT FROM column_cursor
INTO #clmnhdr
END
SET #clmnstring = LEFT(#clmnstring, LEN(#clmnstring) - 1)
SET #valuestring = LEFT(#valuestring, LEN(#valuestring) - 1)
INSERT INTO dbo.tbl_text VALUES('INSERT INTO dbo.' + #tblhdr + ' ' + #clmnstring + ') VALUES' + #valuestring + ')')
FETCH NEXT FROM row_cursor
INTO #rowID
CLOSE column_cursor
DEALLOCATE column_cursor
END
--if it wrote identity_insert on, turn it off
IF (#identity = 1)
BEGIN
INSERT INTO dbo.tbl_text VALUES('SET IDENTITY_INSERT dbo.' + #tblhdr + ' OFF')
END
CLOSE row_cursor
DEALLOCATE row_cursor
END
IF object_id('tempdb..##temptable') IS NOT NULL
BEGIN
DROP TABLE ##temptable
END
GO
If you've got an account on SSC, you can use the script I published last year. It works without cursors an it enables custom filtering.
http://www.sqlservercentral.com/scripts/Script+Data/65998/
Hope this helps
Assuming Row is an INT NOT NULL. You could write a SELECT statement that outputs SQL;
SELECT N'INSERT INTO Table1 VALUES (' + CAST(Row AS NVARCHAR(10)) + N');'
FROM Table1
Then output your results to text.