SQL Server scope issue with Dynamic SQL - 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.

Related

Can't see the inserted files in my database using Cursor

I have this code and executes with no issues but i dont see the tables or files that are supposed to be in the 'Names' Database here is the queries
And this is the data im trying to insert in bulk
also here is the code:
CREATE PROCEDURE import_txt_files12
AS
BEGIN
DECLARE #file varchar(255)
DECLARE #path varchar(255)
DECLARE #sql varchar(8000)
DECLARE #tablename varchar(255)
SET #path = 'C:\Users\marti\OneDrive\Desktop\Data Analist course\Datasets\names\'
DECLARE file_cursor CURSOR FOR
SELECT physical_name FROM sys.master_files
WHERE [name] LIKE 'yob%' AND physical_name LIKE #path + '%'
OPEN file_cursor
FETCH NEXT FROM file_cursor INTO #file
WHILE ##FETCH_STATUS = 0
BEGIN
-- Extract table name from file name
SET #tablename = SUBSTRING(#file, LEN(#path), LEN(#file) - LEN(#path) - 4)
SET #sql = 'BULK INSERT [Names].[dbo].[' + #tablename + '] FROM ''' + #file + ''' WITH (FORMAT = ''txt'', FIRSTROW = 1, FIELDTERMINATOR = '','', ROWTERMINATOR = ''\n'')'
EXEC (#sql)
FETCH NEXT FROM file_cursor INTO #file
END
CLOSE file_cursor
DEALLOCATE file_cursor
END

Loop through Query and Update field

I'm trying to loop through a fields defined in a query to an update statement.
I have the following SQL:
Declare #SQL varchar(max)
#SQL= 'Select [a],[b],[c],[d],[e]....[z]
From Table1;'
I want to be able to loop through all the fields [a]-[z] and update via the following statement:
Update Table 1
Set [a] = Case when [a] = 'Not at all' Then 0
when [a] = 'Very Much' Then 10 End
Field names are not actually [a]..[z]; I can't run the the update statement on the whole table, only a specific set of field names.
Struggling to write it programatically in SQL Server.
Declare #SQL varchar(max)
Declare #name varchar(100)
DECLARE #getid CURSOR
Set #getid = cursor for
SELECT name
FROM
sys.dm_exec_describe_first_result_set('Select [a],[b],[c],[d],[e]....[z]
From Table1', NULL, 0)
Open #getid
FETCH NEXT
FROM #getid INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'Update Table1
Set ' + #name + ' = Case when ' + #name +'= ''Very Much'' Then ''10''
when ' + #name + ' = ''Not at all'' Then ''0''
Else ' + #name + ' End'
Exec(#SQL)
FETCH NEXT
FROM #getid INTO #name
END
CLOSE #getid
DEALLOCATE #getid
Basically dm_exec_describe_first_result_set is grabbing the fieldnames and outputting it as a recordset. Then we are just passing the the each of the records to #name and use it form our update statement and then executing it for each record passed.
Hope this helps someone else! Curious to see if there is a better way.
I think if you want to make it a little more generic I would do something like the following code. This will allow you to not have to write the specific query for every table you want to do this to and you could potentially filter out columns you do not want in the future.
To be clear, I borrowed the SQL to do the actual UPDATE from #Dale-K post and just made it pretty.
DECLARE #strSQL NVARCHAR(1000)
DECLARE #strTable NVARCHAR(100)
DECLARE #strColName VARCHAR(100)
SET #strTable = N'Table1'
CREATE TABLE #COLUMNS(ColName varchar(100))
SET #strSQL = ' select COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and DATA_TYPE in (''nvarchar'', ''varchar'')'
INSERT INTO #COLUMNS
EXEC sp_executeSQL #strSQL, N'#TableName nvarchar(100)', #TableName = #strTable
DECLARE csrColumns CURSOR LOCAL FORWARD_ONLY FOR
SELECT ColName FROM #COLUMNS
OPEN csrColumns
FETCH csrColumns INTO #strColName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #strSQL = N'UPDATE ' + #strTable + '
SET ' + #strColName + ' = CASE WHEN ' + #strColName +'= ''Very Much'' THEN ''10''
WHEN ' + #strColName + ' = ''Not at all'' THEN ''0''
ELSE ' + #strColName + ' END'
exec sp_ExecuteSQL #strSQL
FETCH csrColumns INTO #strColName
END
CLOSE csrColumns
DEALLOCATE csrColumns

Conversion failed when converting the varchar value '"' to datatype int in dynamic query

I am receiving the above error when I try to execute a query on MS SQL Server 2005. It is a dynamic query built up in multiple parts. Here is the simplified structure and data:
CREATE TABLE [record_fields](
[field_id] [int] NOT NULL,
[campaign_id] [int] NOT NULL,
[record_import_type_id] [int] NOT NULL,
[fieldname] [varchar](150) NOT NULL,
[import_file_column_index] [smallint] NOT NULL,
[records_fieldname] [varchar](50) NOT NULL,
[show_field] [bit] NOT NULL,
[field_order] [int] NOT NULL,
[dialler_field_required] [bit] NULL,
[dialler_field_name] [varchar](50) NULL,
[dialler_field_order] [int] NULL,
[field_group_id] [int] NOT NULL
);
INSERT INTO [record_fields] VALUES(1,2,1,'Record Id',47,'record_id',0,1,1,'Record Id',NULL,1);
INSERT INTO [record_fields] VALUES(2,2,1,'Field Name 1',46,'field01',0,1,1,'Field 1',NULL,1);
INSERT INTO [record_fields] VALUES(3,2,1,'Field Name 2',46,'field02',0,1,1,'Field 2',NULL,1);
CREATE TABLE [records](
[record_id] [int] NOT NULL,
[campaign_id] [int] NOT NULL,
[dialler_entry_created] BIT NOT NULL,
[field01] [VARCHAR](50) NULL,
[field02] [VARCHAR](50) NULL
);
INSERT INTO [records] VALUES(1,2,0,'Field01 Value','Field02 Value');
INSERT INTO [records] VALUES(1,2,0,'Field01 Value','Field02 Value');
And the query I am attempting to run is as follows:
DECLARE #campaignId INT
SET #campaignId = 2
DECLARE #FieldName VARCHAR(250)
DECLARE #ColumnName VARCHAR(250)
DECLARE #SelectQuery VARCHAR(2000)
DECLARE #InsertQuery VARCHAR(2000)
SET #SelectQuery = ''
SET #InsertQuery = ''
declare #FieldNames cursor for SELECT records_fieldname, dialler_field_name FROM record_fields where campaign_id = #campaignid AND dialler_field_required = 1 ORDER BY dialler_field_order
open #FieldNames
fetch next from #FieldNames into #FieldName, #ColumnName
while ##fetch_status = 0
begin
-- Build up a dymamic string of columns to read in the select query
SET #SelectQuery = #SelectQuery + '''"''+' + #FieldName + '+''"'', '
-- Build up a dynamic string of column names to add to our temp table
SET #InsertQuery = #InsertQuery + '[' + #ColumnName + '] varchar(255), '
fetch next from #FieldNames into #FieldName, #ColumnName
end
close #FieldNames
deallocate #FieldNames
IF Len(#SelectQuery) > 1 AND Len(#InsertQuery) > 1
BEGIN
-- Trim the trailing ','
SET #InsertQuery = Left(#InsertQuery,Len(#InsertQuery)-1)
SET #SelectQuery = Left(#SelectQuery,Len(#SelectQuery)-1)
EXEC ('DECLARE #RecordData TABLE (' + #InsertQuery + ');'
+ 'INSERT INTO #RecordData SELECT ' + #SelectQuery + ' from records WHERE campaign_id =' + #campaignId + ' AND ISNULL(dialler_entry_created, 0) = 0; '
+ 'SELECT * FROM #RecordData;')
END
The problem seems to stem from trying to select on record_id, which gives the 'Conversion failed when converting the varchar value '"' to datatype int' error
If I do not include the record_id column (which is the only INT column in the select list) it seems to work ok.
I have tried to apply CONVERT(VARCHAR(250), record_id) but cannot seem to get the syntax correct.
Any help would be greatly appreciated
There were 2 errors. In constructing select query and campaignid in exec function:
DECLARE #campaignId INT
SET #campaignId = 2
DECLARE #FieldName VARCHAR(250)
DECLARE #ColumnName VARCHAR(250)
DECLARE #SelectQuery VARCHAR(2000)
DECLARE #InsertQuery VARCHAR(2000)
SET #SelectQuery = ''
SET #InsertQuery = ''
declare #FieldNames cursor for SELECT records_fieldname, dialler_field_name FROM record_fields where campaign_id = #campaignid AND dialler_field_required = 1 ORDER BY dialler_field_order
open #FieldNames
fetch next from #FieldNames into #FieldName, #ColumnName
while ##fetch_status = 0
begin
-- Build up a dymamic string of columns to read in the select query
SET #SelectQuery = #SelectQuery + #FieldName + ', '
-- Build up a dynamic string of column names to add to our temp table
SET #InsertQuery = #InsertQuery + '[' + #ColumnName + '] varchar(255), '
fetch next from #FieldNames into #FieldName, #ColumnName
end
close #FieldNames
deallocate #FieldNames
IF Len(#SelectQuery) > 1 AND Len(#InsertQuery) > 1
BEGIN
-- Trim the trailing ','
SET #InsertQuery = Left(#InsertQuery,Len(#InsertQuery)-1)
SET #SelectQuery = Left(#SelectQuery,Len(#SelectQuery)-1)
Declare #result nvarchar(max) ='DECLARE #RecordData TABLE (' + #InsertQuery + ');'
+ 'INSERT INTO #RecordData SELECT ' + #SelectQuery + ' from records WHERE campaign_id =' + cast(#campaignId as nvarchar(50))+ ' AND ISNULL(dialler_entry_created, 0) = 0; '
+ 'SELECT * FROM #RecordData;'
Exec(#result)
END
Here is working fiddle: http://sqlfiddle.com/#!6/e450c/23
I think this is your problem:
DECLARE #campaignId INT
SET #campaignId = 2
. . .
+ 'INSERT INTO #RecordData SELECT ' + #SelectQuery + ' from records WHERE campaign_id =' + #campaignId + ' AND ISNULL(dialler_entry_created, 0) = 0; '
Notice the + #campaignId.
Try this instead:
DECLARE #campaignId varchar(255);
SET #campaignId = '2';
SET #SelectQuery = #SelectQuery + '''"''+' + #FieldName + '+''"'', '
Change to
SET #SelectQuery = #SelectQuery + ' ' + #FieldName + ' ,'
If you want an often discouraged (but nonetheless very handy) shortcut to converting numbers to string, change the bit at the bottom from
#campaignId
to
RTRIM#campaignId)
Does the character conversion and trims off trailing etc all in one word.

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

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

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.