Is there a way to create multiple triggers in one script? - database

I am trying to create multiple triggers with only uploading one script into an Oracle DB / APEX workspace, and running it once.
Here is a brief script compared to the one im trying to use:
create or replace trigger "BI_TEC_ROLES"
before insert on "TEC_ROLES"
for each row
begin
if :NEW."ROLE_ID" is null then
select "TEC_ROLES_SEQ".nextval into :NEW."ROLE_ID" from dual;
end if;
end;
create or replace trigger "BI_TEC_STATUSES"
before insert on "TEC_STATUSES"
for each row
begin
if :NEW."STATUS_ID" is null then
select "TEC_STATUSES_SEQ".nextval into :NEW."STATUS_ID" from dual;
end if;
end;
create or replace trigger "BI_TEC_SUBS"
before insert on "TEC_SUBS"
for each row
begin
if :NEW."SUB_ID" is null then
select "TEC_SUBS_SEQ".nextval into :NEW."SUB_ID" from dual;
end if;
end;
I have tried putting GO in between each individual block, but still only creates the first trigger then gives me an error for the second saying:
Error(7,1): PLS-00103: Encountered the symbol "CREATE"
I am hoping that it is possible to do this. Thank you very much for your time and interest =)

Add a forward slash on a new line after each trigger to execute the command in the buffer:
create trigger...
...
end;
/

Put a slash '/' as the first character on a blank line between each trigger statement. This is the SQL*PLUS equivalent of 'go'.

Yes we can execute multiple procedure/trigger/function in single script using the FORWARD SLASH / inside the sql file.
Like below:
create or replace trigger "BI_TEC_ROLES"
before insert on "TEC_ROLES"
for each row
begin
if :NEW."ROLE_ID" is null then
select "TEC_ROLES_SEQ".nextval into :NEW."ROLE_ID" from dual;
end if;
end;
/
create or replace trigger "BI_TEC_STATUSES"
before insert on "TEC_STATUSES"
for each row
begin
if :NEW."STATUS_ID" is null then
select "TEC_STATUSES_SEQ".nextval into :NEW."STATUS_ID" from dual;
end if;
end;
/
create or replace trigger "BI_TEC_SUBS"
before insert on "TEC_SUBS"
for each row
begin
if :NEW."SUB_ID" is null then
select "TEC_SUBS_SEQ".nextval into :NEW."SUB_ID" from dual;
end if;
end;
/
Then oracle will consider it as new statement/block.

Place a forward slash
/
between the two statements on a separate line.
Oracle will then accept it as a new statement

--Parameter:
-- #InclDrop bit
-- Possible values
-- 0 - Script to drop the triggers is not generated.
-- 1 - Script to drip the triggers is generated.
SET ansi_nulls ON
go
SET quoted_identifier ON
go
ALTER PROCEDURE [dbo].[Createscriptofalltriggers]
#InclDrop BIT =1
AS
DECLARE #SQL VARCHAR(8000),
#Text NVARCHAR(4000),
#BlankSpaceAdded INT,
#BasePos INT,
#CurrentPos INT,
#TextLength INT,
#LineId INT,
#MaxID INT,
#AddOnLen INT,
#LFCR INT,
#DefinedLength INT,
#SyscomText NVARCHAR(4000),
#Line NVARCHAR(1000),
#UserName SYSNAME,
#ObjID INT,
#OldTrigID INT
SET nocount ON
SET #DefinedLength = 1000
SET #BlankSpaceAdded = 0
IF #InclDrop <> 0
SET #InclDrop =1
-- This Part Validated the Input parameters
DECLARE #Triggers TABLE
(
username SYSNAME NOT NULL,
trigname SYSNAME NOT NULL,
objid INT NOT NULL
)
DECLARE #TrigText TABLE
(
objid INT NOT NULL,
lineid INT NOT NULL,
linetext NVARCHAR(1000) NULL
)
INSERT INTO #Triggers
(username,
trigname,
objid)
SELECT DISTINCT A.NAME,
B.NAME,
B.id
FROM dbo.sysusers A,
dbo.sysobjects B,
dbo.syscomments C
WHERE A.uid = B.uid
AND B.type = 'Tr'
AND B.id = C.id
AND C.encrypted = 0
IF EXISTS(SELECT C.*
FROM syscomments C,
sysobjects O
WHERE O.id = C.id
AND O.type = 'Tr'
AND C.encrypted = 1)
BEGIN
PRINT '/*'
PRINT 'The following encrypted triggers were found'
PRINT 'The procedure could not write the script for it'
SELECT DISTINCT A.NAME,
B.NAME,
B.id
FROM dbo.sysusers A,
dbo.sysobjects B,
dbo.syscomments C
WHERE A.uid = B.uid
AND B.type = 'Tr'
AND B.id = C.id
AND C.encrypted = 1
PRINT '*/'
END
DECLARE ms_crs_syscom CURSOR local forward_only FOR
SELECT T.objid,
C.text
FROM #Triggers T,
dbo.syscomments C
WHERE T.objid = C.id
ORDER BY T.objid,
C.colid
FOR READ only
SELECT #LFCR = 2
SELECT #LineId = 1
OPEN ms_crs_syscom
SET #OldTrigID = -1
FETCH next FROM ms_crs_syscom INTO #ObjID, #SyscomText
WHILE ##fetch_status = 0
BEGIN
SELECT #BasePos = 1
SELECT #CurrentPos = 1
SELECT #TextLength = Len(#SyscomText)
IF #ObjID <> #OldTrigID
BEGIN
SET #LineID = 1
SET #OldTrigID = #ObjID
END
WHILE #CurrentPos != 0
BEGIN
--Looking for end of line followed by carriage return
SELECT #CurrentPos = Charindex(Char(13) + Char(10), #SyscomText,
#BasePos)
--If carriage return found
IF #CurrentPos != 0
BEGIN
WHILE ( Isnull(Len(#Line), 0) + #BlankSpaceAdded
+ #CurrentPos - #BasePos + #LFCR ) >
#DefinedLength
BEGIN
SELECT #AddOnLen = #DefinedLength - (
Isnull(Len(#Line),
0
) +
#BlankSpaceAdded )
INSERT #TrigText
VALUES ( #ObjID,
#LineId,
Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText, #BasePos,
#AddOnLen),
N''))
SELECT #Line = NULL,
#LineId = #LineId + 1,
#BasePos = #BasePos + #AddOnLen,
#BlankSpaceAdded = 0
END
SELECT #Line = Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText, #BasePos,
#CurrentPos
-#BasePos +
#LFCR),
N'')
SELECT #BasePos = #CurrentPos + 2
INSERT #TrigText
VALUES( #ObjID,
#LineId,
#Line )
SELECT #LineId = #LineId + 1
SELECT #Line = NULL
END
ELSE
--else carriage return not found
BEGIN
IF #BasePos <= #TextLength
BEGIN
/*If new value for #Lines length will be > then the
**defined length
*/
WHILE ( Isnull(Len(#Line), 0) + #BlankSpaceAdded
+ #TextLength - #BasePos + 1 ) >
#DefinedLength
BEGIN
SELECT #AddOnLen = #DefinedLength - (
Isnull(Len(#Line),
0
) +
#BlankSpaceAdded )
INSERT #TrigText
VALUES ( #ObjID,
#LineId,
Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText,
#BasePos,
#AddOnLen),
N''))
SELECT #Line = NULL,
#LineId = #LineId + 1,
#BasePos = #BasePos + #AddOnLen,
#BlankSpaceAdded = 0
END
SELECT #Line = Isnull(#Line, N'')
+ Isnull(Substring(#SyscomText,
#BasePos,
#TextLength
-#BasePos+1
), N'')
IF Len(#Line) < #DefinedLength
AND Charindex(' ', #SyscomText, #TextLength + 1)
> 0
BEGIN
SELECT #Line = #Line + ' ',
#BlankSpaceAdded = 1
END
END
END
END
FETCH next FROM ms_crs_syscom INTO #ObjID, #SyscomText
END
IF #Line IS NOT NULL
INSERT #TrigText
VALUES( #ObjID,
#LineId,
#Line )
CLOSE ms_crs_syscom
PRINT '-- You should run this result under dbo if your triggers belong to multiple users'
PRINT ''
IF #InclDrop = 1
BEGIN
PRINT '-- Dropping the Triggers'
PRINT ''
SELECT 'If exists(Select * from sysObjects where id =Object_ID(''['
+ username + '].[' + trigname
+ ']'') and ObjectProperty(Object_ID(''['
+ username + '].[' + trigname + ']''), ''ISTRIGGER'')=1) Drop Trigger ['
+ username + '].[' + trigname + '] ' + Char(13)
+ Char(10) + 'GO' + Char(13) + Char(10) + Char(13)
+ Char(10)
FROM #Triggers
END
PRINT '----------------------------------------------'
PRINT '-- Creation of Triggers'
PRINT ''
PRINT ''
DECLARE ms_users CURSOR local forward_only FOR
SELECT T.username,
T.objid,
Max(D.lineid)
FROM #Triggers T,
#TrigText D
WHERE T.objid = D.objid
GROUP BY T.username,
T.objid
FOR READ only
OPEN ms_users
FETCH next FROM ms_users INTO #UserName, #ObjID, #MaxID
WHILE ##fetch_status = 0
BEGIN
PRINT 'SetUser N''' + #UserName + '''' + Char(13)
+ Char(10)
SELECT '-- Text of the Trigger'= CASE lineid
WHEN 1 THEN 'GO' + Char(13) + Char(
10)
+
linetext
WHEN #MaxID THEN linetext + 'GO'
ELSE linetext
END
FROM #TrigText
WHERE objid = #ObjID
ORDER BY lineid
PRINT 'Setuser'
FETCH next FROM ms_users INTO #UserName, #ObjID, #MaxID
END
CLOSE ms_users
PRINT 'GO'
PRINT '------End ------'
DEALLOCATE ms_crs_syscom
DEALLOCATE ms_users
SET nocount ON
DECLARE #return_value INT
How to execute it:
EXEC #return_value = [dbo].[Createscriptofalltriggers]
#InclDrop = 1
SELECT 'Return Value' = #return_value
go

Related

SQL error when trying to loop in databases and create function

I have created a SQL script to loop throw databases and create a function (the aim of the function is to convert RTF to Plain Text).
I put the script of the function creation on a variable and try to execute it using the exec command.
I have used While loop and I have put the request on a varchar variable, then, exec #command
but I get this error:
enter image description here
declare #Total as int
select #Total = count(*) from Temp1
declare #counter as int
set #counter = 1
declare #CurrentVal as varchar(max)
declare #command varchar(max)
while (#counter <= #Total)
begin
select #CurrentVal = name from Temp1 where RowId = #counter
set #command=' use '+#CurrentVal+'
GO
CREATE FUNCTION dbo.fnParseTEXTRTF
(
#rtf VARCHAR(max)
)
RETURNS VARCHAR(max)
AS
BEGIN
DECLARE #Stage TABLE
(
Chr CHAR(1),
Pos INT
)
INSERT #Stage
(
Chr,
Pos
)
SELECT SUBSTRING(#rtf, Number, 1),
Number
FROM master..spt_values
WHERE Type = ''p''
AND SUBSTRING(#rtf, Number, 1) IN (''{'', ''}'')
DECLARE #Pos1 INT,
#Pos2 INT
SELECT #Pos1 = MIN(Pos),
#Pos2 = MAX(Pos)
FROM #Stage
DELETE
FROM #Stage
WHERE Pos IN (#Pos1, #Pos2)
WHILE 1 = 1
BEGIN
SELECT TOP 1 #Pos1 = s1.Pos, #Pos2 = s2.Pos
FROM #Stage AS s1
INNER JOIN #Stage AS s2 ON s2.Pos > s1.Pos
WHERE s1.Chr = ''{''
AND s2.Chr = ''}''
ORDER BY s2.Pos - s1.Pos
IF ##ROWCOUNT = 0
BREAK
DELETE
FROM #Stage
WHERE Pos IN (#Pos1, #Pos2)
UPDATE #Stage
SET Pos = Pos - #Pos2 + #Pos1 - 1
WHERE Pos > #Pos2
SET #rtf = STUFF(#rtf, #Pos1, #Pos2 - #Pos1 + 1, '''')
END
SET #Pos1 = PATINDEX(''%\cf[0123456789][0123456789 ]%'', #rtf)
WHILE #Pos1 > 0
SELECT #Pos2 = CHARINDEX('' '', #rtf, #Pos1 + 1), #rtf = STUFF(#rtf, #Pos1, #Pos2 - #Pos1 + 1, ''''), #Pos1 = PATINDEX(''%\cf[0123456789][0123456789 ]%'', #rtf)
SELECT #rtf = REPLACE(#rtf, ''\pard'', ''''), #rtf = REPLACE(#rtf, ''\par'', ''''), #rtf = case when LEN(#rtf)>0 then LEFT(#rtf, LEN(#rtf) - 1) else #rtf end
SELECT #rtf = REPLACE(#rtf, ''\b0 '', ''''), #rtf = REPLACE(#rtf, ''\b '', '''')
SELECT #rtf = STUFF(#rtf, 1, CHARINDEX('' '', #rtf), '''')
RETURN #rtf
end'
set #counter = #counter + 1
exec #command
end
As i understand, the function is correct, the main problem to execute statement for function creation across multiple databases.
GO can't be used here, it's not sql, it's instruction to client to execute all statements in scope
Unfortunately, you can't create function not in current database, using [DatabaseName].[schema].[FuncName].
I can propose such technique to solve the problem, code just for example
declare #funccode nvarchar(4000);
set #funccode='CREATE FUNCTION [dbo].[fntest]
(
)
RETURNS int
AS
BEGIN
RETURN 1
END;'
declare #dbname nvarchar(100)='TestDatabase'
declare #statement nvarchar(max) ='use '+#dbname+';
exec (#func);'
exec sp_executesql #stmt = #statement,#params=N'#func nvarchar(4000)',#func=#funccode;
Th idea - to switch current database inside exec statement and call new exec statement, when current database is already set

How to exclude commented line/text in finding procedure with Text in SQL Server?

I have two procedures as shown below.
Create proc FirstProcdure
As
begin
select * from MyTableA
--select * from MyTableB
end
and
Create proc SecondProcdure
As
begin
select * from MyTableB
--select * from MyTableA
end
Now I want to search procedure with text - MyTableA. It should only come 'FirstProcdure' in result because in 'SecondProcdure' the
text MyTableA is commented.
I have tried using below query
Select * from sysobjects where OBJECT_DEFINITION (id) like '%MyTableA%'
Currently it is giving both procedure name in search result.
Sometime we need to change procedure definition quickly & then it is difficult to open find and replace several procedures. So I need to search only procedure name for which the searched text is not the part of commented lines.
You can use the custom function for ignore comment text search.
CREATE FUNCTION SearchCommentText(#Value VARCHAR(MAX),#SearchText VARCHAR(MAX))
RETURNS INT
AS
BEGIN
DECLARE #cursor INT = 0,#ret INT=0
declare #commenttext varchar(max)=''
WHILE PATINDEX('%--%', #Value) > 0 OR PATINDEX('%/*%', #Value) > 0
BEGIN
IF CHARINDEX('--', #Value, 0)BETWEEN 1 AND CHARINDEX('/*', #Value, 0)
OR CHARINDEX('/*', #Value, 0) = 0
BEGIN
SET #commenttext=#commenttext+ SUBSTRING( #Value,CHARINDEX('--', #Value), ISNULL(NULLIF(CHARINDEX(CHAR(13) + CHAR(10), #Value, CHARINDEX('--',#Value)), 0), LEN(#Value)) - CHARINDEX('--', #Value) + 2)
SET #Value = STUFF(#Value, CHARINDEX('--', #Value), ISNULL(NULLIF(CHARINDEX(CHAR(13) + CHAR(10), #Value, CHARINDEX('--', #Value)), 0), LEN(#Value)) - CHARINDEX('--', #Value) + 2, '') ;
END ;
ELSE
BEGIN
SET #cursor = -1 ;
WHILE CHARINDEX('/*', #Value, #cursor + 1)BETWEEN 1 AND CHARINDEX('*/', #Value, #cursor + 1)
SET #cursor = CHARINDEX('/*', #Value, #cursor + 1) ;
set #commenttext=#commenttext+SUBSTRING(#Value, #cursor, CHARINDEX('*/', #Value, #cursor) - #cursor + 2);
SET #Value = STUFF(#Value, #cursor, CHARINDEX('*/', #Value, #cursor) - #cursor + 2, '') ;
END ;
END ;
IF(#commenttext LIKE '%'+#SearchText+'%' AND #Value NOT LIKE '%'+#SearchText+'%')
SET #ret=1;
RETURN #ret;
END;
Execute the following query.
SELECT DISTINCT OBJECT_NAME(sc.id) FROM syscomments sc
WHERE TEXT like '%MyTableA%' AND dbo.SearchCommentText(sc.text,'MyTableA') <>1
What you are looking for a dataobject used in other dataobject is a dependency, so, is too much easier to do it directly
SELECT OBJECT_NAME(id) FROM sys.sysdepends WHERE depid = OBJECT_ID('MyTableA')
If you want to search for a string or another thing that is not dataobject related (For example, depends will not detect if you call your table using dynamic SQL). I prefer to use sp_helptext instead of OBJECT_DEFINITION, if you don't have objections using a loop
DECLARE #SearchFor VARCHAR(100) = 'MyTableA'
DECLARE #Objects TABLE(name varchar(100))
DECLARE #Result TABLE(name varchar(100))
DECLARE #Lines TABLE(id int identity, line varchar(maX))
INSERT #Objects
SELECT name FROM sys.objects WHERE Type in ('FN', 'IF', 'V', 'P', 'TR', 'TF')
DECLARE #ObjectName VARCHAR(100)
WHILE EXISTS (SELECT 1 FROM #Objects)
BEGIN
SELECT TOP 1 #ObjectName = name FROM #Objects
DELETE #Lines
INSERT #Lines (line)
exec sp_helptext #ObjectName
--Wipe out multiline comments
DECLARE #Linestart INT, #indexStart INT, #LineEnd INT, #indexEnd INT
WHILE EXISTS(SELECT 1 FROM #Lines WHERE charindex('/*', line) > 0)
BEGIN
SELECT TOP 1 #Linestart = id, #indexStart = charindex('/*', line)
FROM #Lines WHERE charindex('/*', line) > 0
ORDER BY id
SELECT TOP 1 #LineEnd = id, #indexEnd = charindex('*/', line)
FROM #Lines WHERE charindex('*/', line) > 0
ORDER BY id
IF #Linestart = #LineEnd
UPDATE #Lines SET line = SUBSTRING(line, 1, #indexStart-1) + SUBSTRING(line, #indexEnd+2, LEN(line))
WHERE id = #Linestart
ELSE
BEGIN
UPDATE #Lines SET line = SUBSTRING(line, 1, #indexStart-1)
WHERE id = #Linestart
UPDATE #Lines SET line = SUBSTRING(line, #indexEnd+2, LEN(line))
WHERE id = #LineEnd
DELETE #Lines WHERE id > #Linestart AND id < #LineEnd
END
END
IF EXISTS (
SELECT 1
FROM #Lines
OUTER APPLY (
SELECT charindex(#SearchFor, line) A, charindex ('--', line) B
) S
WHERE A > 0 AND (B = 0 OR A < B) )
BEGIN
INSERT #Result VALUES (#ObjectName)
END
DELETE #Objects WHERE name = #ObjectName
END
SELECT * FROM #Result

Temp Table - Temporary table is empty - SQL Server

I know this question I'm about to ask is quite common, but I haven't been able to use other examples to my own.
I have a stored procedure that uses a table Enum_Tables (this table has other table names) to search the entire database for a specific string. The results are stored in a table which gives me the specific rows of Enum_Tables that I want.
Currently the stored is working properly, but right now it is creating SearchTMP in the Database. And I don't want that, What I want is creating a temporary table like #SearchTMP. I created the temporary table, I tried to populated it, but It is empty.
The part I'm talking about is inside the while logic (WHILE EXISTS (SELECT 1 FROM #SQLTbl WHERE ISNULL(Execstatus ,0) = 0) ).
It's checking if there is values in SearchTMP, and since it's not a temporary table, it's creating one in the database. I want to change it to a #SearchTMP. I I created the table, but I'm not being able to populated it, since I wan't being able to do it, I deleted that code. I know I need to do an insert, but how can I do it without changing to much code, and maintain the same logic.
This is my stored procedure code:
ALTER PROCEDURE [dbo].[SearchTables_TEST]
--#Tablenames VARCHAR(500)
#SearchStr NVARCHAR(60),
#GenerateSQLOnly Bit = 0,
#SchemaNames VARCHAR(500) ='%'
AS
SET NOCOUNT ON
DECLARE #MatchFound BIT
SELECT #MatchFound = 0
DECLARE #CheckTableNames Table (Schemaname sysname, Tablename sysname)
DECLARE #SearchStringTbl TABLE (SearchString VARCHAR(500))
DECLARE #SQLTbl TABLE (Tablename SYSNAME,
WHEREClause VARCHAR(MAX),
SQLStatement VARCHAR(MAX),
Execstatus BIT
)
DECLARE #SQL VARCHAR(MAX)
DECLARE #TableParamSQL VARCHAR(MAX)
DECLARE #SchemaParamSQL VARCHAR(MAX)
DECLARE #TblSQL VARCHAR(MAX)
DECLARE #tmpTblname sysname
DECLARE #ErrMsg VARCHAR(100)
IF LTRIM(RTRIM(#SchemaNames)) =''
BEGIN
SELECT #SchemaNames = '%'
END
--IF CHARINDEX(',',#Tablenames) > 0
-- SELECT #TableParamSQL = 'SELECT ''' + REPLACE(#Tablenames,',','''as TblName UNION SELECT ''') + ''''
--ELSE
-- SELECT #TableParamSQL = 'SELECT ''' + #Tablenames + ''' as TblName '
IF CHARINDEX(',',#SchemaNames) > 0
SELECT #SchemaParamSQL = 'SELECT ''' + REPLACE(#SchemaNames,',','''as SchemaName UNION SELECT ''') + ''''
ELSE
SELECT #SchemaParamSQL = 'SELECT ''' + #SchemaNames + ''' as SchemaName '
SELECT #TblSQL = 'SELECT SCh.NAME,T.NAME
FROM SYS.TABLES T
JOIN SYS.SCHEMAS SCh
ON SCh.SCHEMA_ID = T.SCHEMA_ID
INNER JOIN [DynaForms].[dbo].[Enums_Tables] et on
(et.Id = T.NAME COLLATE Latin1_General_CI_AS) '
INSERT INTO #CheckTableNames
(Schemaname,Tablename)
EXEC(#TblSQL)
IF NOT EXISTS(SELECT 1 FROM #CheckTableNames)
BEGIN
SELECT #ErrMsg = 'No tables are found in this database ' + DB_NAME() + ' for the specified filter'
PRINT #ErrMsg
RETURN
END
IF LTRIM(RTRIM(#SearchStr)) =''
BEGIN
SELECT #ErrMsg = 'Please specify the search string in #SearchStr Parameter'
PRINT #ErrMsg
RETURN
END
ELSE
BEGIN
SELECT #SearchStr = REPLACE(#SearchStr,',,,',',#DOUBLECOMMA#')
SELECT #SearchStr = REPLACE(#SearchStr,',,','#DOUBLECOMMA#')
SELECT #SearchStr = REPLACE(#SearchStr,'''','''''')
SELECT #SQL = 'SELECT ''' + REPLACE(#SearchStr,',','''as SearchString UNION SELECT ''') + ''''
INSERT INTO #SearchStringTbl
(SearchString)
EXEC(#SQL)
UPDATE #SearchStringTbl
SET SearchString = REPLACE(SearchString ,'#DOUBLECOMMA#',',')
END
INSERT INTO #SQLTbl
( Tablename,WHEREClause)
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME),
(
SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' OR ' + CHAR(10)
FROM SYS.columns SC
JOIN SYS.types STy
ON STy.system_type_id = SC.system_type_id
AND STy.user_type_id =SC.user_type_id
CROSS JOIN #SearchStringTbl SearchSTR
WHERE STY.name in ('varchar','char','nvarchar','nchar','text')
AND SC.object_id = ST.object_id
ORDER BY SC.name
FOR XML PATH('')
)
FROM SYS.tables ST
JOIN #CheckTableNames chktbls
ON chktbls.Tablename = ST.name
JOIN SYS.schemas SCh
ON ST.schema_id = SCh.schema_id
AND Sch.name = chktbls.Schemaname
WHERE ST.name <> 'SearchTMP'
GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME) ;
UPDATE #SQLTbl SET SQLStatement = 'SELECT * INTO SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5) -- this line was uncomment
DELETE FROM #SQLTbl
WHERE WHEREClause IS NULL
DECLARE #output TABLE (Id VARCHAR(50), Name VARCHAR(100))
Create Table #SearchTMP (searchparameter varchar(200))
WHILE EXISTS (SELECT 1 FROM #SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
BEGIN
SELECT TOP 1 #tmpTblname = Tablename , #SQL = SQLStatement
FROM #SQLTbl
WHERE ISNULL(Execstatus ,0) = 0
IF #GenerateSQLOnly = 0
BEGIN
IF OBJECT_ID('SearchTMP','U') IS NOT NULL -- this line was uncomment
DROP TABLE SearchTMP -- this line was uncomment
EXEC (#SQL)
IF EXISTS(SELECT 1 FROM SearchTMP)
BEGIN
--SELECT parsename(#tmpTblname,1) FROM SearchTMP
SELECT #MatchFound = 1
INSERT INTO #output (Id, Name)
Select * from [DynaForms].[dbo].[Enums_Tables] where id in (SELECT parsename(#tmpTblname,1) FROM SearchTMP)
END
END
ELSE
BEGIN
PRINT REPLICATE('-',100)
PRINT #tmpTblname
PRINT REPLICATE('-',100)
PRINT replace(#SQL,'INTO SearchTMP','')
END
UPDATE #SQLTbl
SET Execstatus = 1
WHERE Tablename = #tmpTblname
END
SELECT * FROM #output
IF #MatchFound = 0
BEGIN
SELECT #ErrMsg = 'No Matches are found in this database ' + DB_NAME() + ' for the specified filter'
PRINT #ErrMsg
RETURN
END
SET NOCOUNT OFF
When you want to use a temp table in a dynamic query, you have to create said temp table first, then populate it in the dynamic query.
CREATE TABLE #MyTempTable (ID INT NOT NULL);
DECLARE #STMT NVARCHAR(MAX) = N'INSERT INTO #MyTempTable (ID) SELECT ID FROM MyTable;';
EXEC sp_executesql
#stmt = #STMT
;
SELECT ID FROM #MyTempTable;
Since the temp table is created in the stored procedure, it is scoped to that stored procedure and will be dropped automatically when the SP finishes.
If you want to use said temp table outside of the SP, you have to create it outside of the SP. (If it is part of the batch, the temp table will be dropped when the connection is closed or you can drop it explicitly).

Improve or replace a complex, slow SQL cursor with set statements

I have a cursor that uses two tables. The logic behind it is for travelling routes for a business application. Lets say you have four destinations - City A, City B, City C and City D. Sometimes you drive from A to B and back again. But other times you drive from A to B to C to D and then back to A - this would be called a Rounder.
In the business application out and back (back and forth from A to B) is priced differently then if you did a Rounder. In one table there are the routes - A to B , C to D etc. In the other table there is the costing estimates. If they just went A to B - use this price, for a Rounder use this price.
Call it a Route table, with the routes driven, and a Costing table, with the prices for all the routes and rounders.
I need to loop through all the trips and look to see if there is a matching '2nd half' of a Rounder. They aren't necessarily in order - they might go C to D then A to B - but this still counts as a Rounder. Or they might go A to B, X to Y, then C to D. The A to B and the subsequent C to D count as a Rounder.
The way I do is to start with the first row in the Route table and loop through the table see if any of the rows match with the 2nd half of a Rounder. If there is no match then, it is just a simple out and back. I use a cursor to do this - and it is SLOW - but I can't think of any way to turn this into a set based SQL statement.
Here's my code if you are up for a re-write to remove a cursor challenge.....
create table #RouteLegs (
RowNbr int,
RouteID varchar(20) INDEX IDX_RouteID NONCLUSTERED,
TripDate datetime INDEX IDX_TripDate CLUSTERED,
WaybillNbr varchar(16) INDEX IDX_WaybillNbr NONCLUSTERED,
MatchedRowNbr int,
CostingModelID int,
Legs varchar(5),
RounderCode varchar(100)
)
insert into #RouteLegs
select ROW_NUMBER() over (order by actual.TripDate) as RowNbr,
actual.RouteID,
cast(actual.TripDate as date) as trip_date,
actual.Waybill_Number,
0, 0, '', ''
from staging.RouteSoureTable
declare #NbrMatches int,
#CurrRouteID varchar(20),
#CurrRowNbr int,
#CurrTripDate datetime,
#CurrWaybillNbr varchar(16),
#MatchRouteID varchar(20),
#MatchRowNbr int,
#MatchTripDate datetime,
#CostingModelID int,
#MatchFound int = 0,
#FrontLegs varchar(10),
#BackLegs varchar(10)
declare csrRouteLeg cursor for
select RouteID, RowNbr, TripDate, WaybillNbr
from #RouteLegs
order by RowNbr
open csrRouteLeg
fetch next from csrRouteLeg
into #CurrRouteID, #CurrRowNbr, #CurrTripDate, #CurrWaybillNbr
while ##FETCH_STATUS = 0
begin
-- print 'begin matching' + cast(#CurrRowNbr as varchar(10))
--reset flag and start looking
set #MatchFound = 0
--check if already matched to another route leg
select #MatchFound = MatchedRowNbr from #RouteLegs where RowNbr = #CurrRowNbr
if #MatchFound = 0
begin
if #MatchFound = 0
begin
--otherwise find the correct costing model baased on matching backhauls
declare csrFindMatch cursor for
select RouteID, RowNbr, TripDate
from #RouteLegs
where RowNbr <> #CurrRowNbr
and MatchedRowNbr = 0
order by RowNbr
-- print 'new matching recordset'
open csrFindMatch
fetch next from csrFindMatch
into #MatchRouteID, #MatchRowNbr, #MatchTripDate
while ##FETCH_STATUS = 0
begin
--this is a front haul with a matching backhaul
--print 'DATEDIFF ' + CAST( ABS(DATEDIFF(D,#CurrTripDate,#MatchTripDate)) AS VARCHAR(10)) + ' row ' + cast(#MatchRowNbr as varchar(20))
if #MatchFound = 0 AND ABS(DATEDIFF(D,#CurrTripDate,#MatchTripDate)) < #DayGapBetweenBackHaul
begin
select #MatchFound = coalesce(max(CostingModelID), 0)
from xref_Costing_withBH xr
inner join DimCosting dim
on xr.CostingModelID = dim.CostingModelCode
where FirstLegRouteCode = #CurrRouteID and BackLegRouteCode = #MatchRouteID
--and #CurrTripDate between dim.CostingModelEffectiveDate and dim.CostingModelExpiryDate
select #FrontLegs = max([Costing Model Leg]), #BackLegs = max([BH Legs]) from [staging].[operations_file_CostingModelRouteLinkage] where [Costing Model #] = #MatchFound
if #MatchFound > 0
begin
--print 'Front - ' + cast(#CurrRouteID as varchar(20)) + ' Back - ' + cast( #MatchRouteID as varchar(20)) + ' Row - ' + cast(#CurrRowNbr as varchar(20)) + ' front haul with a matching backhaul'
set #RounderCode = 'Backhaul-' + ltrim(rtrim(cast(#AssetCode as varchar(20)))) + '-' + cast(#MatchFound as varchar(20)) + '-' + cast(#BatchID as varchar(20))+ '-' + cast(#CurrRowNbr as varchar(20))
update #RouteLegs
set MatchedRowNbr = #MatchRowNbr,
Legs = #FrontLegs,
CostingModelID = #MatchFound,
RounderCode = #RounderCode
where RowNbr = #CurrRowNbr
update #RouteLegs
set MatchedRowNbr = #CurrRowNbr,
Legs = #BackLegs,
CostingModelID = #MatchFound,
RounderCode = #RounderCode
where RowNbr = #MatchRowNbr
-- select * from #RouteLegs
--print 'front haul updated'
end
else
--this could be a back haul with a matching front haul - but first check this row hasn't been matched in a previous loop
select #MatchFound = COALESCE(MatchedRowNbr, 0) from #RouteLegs where RowNbr = #CurrRowNbr
if #MatchFound = 0
begin
select #MatchFound = coalesce(max(CostingModelID) , 0)
from xref_Costing_withBH xr
inner join DimCosting dim
on xr.CostingModelID = dim.CostingModelCode
where FirstLegRouteCode = #MatchRouteID and BackLegRouteCode = #CurrRouteID
--and #CurrTripDate between dim.CostingModelEffectiveDate and dim.CostingModelExpiryDate
select #FrontLegs = max([Costing Model Leg]), #BackLegs = max([BH Legs]) from [staging].[operations_file_CostingModelRouteLinkage] where [Costing Model #] = #MatchFound
if #MatchFound > 0 AND ABS(DATEDIFF(D,#CurrTripDate,#MatchTripDate)) < #DayGapBetweenBackHaul
begin
--print 'Front - ' + cast(#MatchRouteID as varchar(20)) + ' Back - ' + cast( #CurrRouteID as varchar(20)) + ' Row - ' + cast(#CurrRowNbr as varchar(20)) + ' this is a back haul with a matching front haul'
set #RounderCode = 'Backhaul-' + ltrim(rtrim(cast(#AssetCode as varchar(20)))) + '-' + cast(#MatchFound as varchar(20)) + '-' + cast(#BatchID as varchar(20))+ '-' + cast(#CurrRowNbr as varchar(20))
update #RouteLegs
set MatchedRowNbr = #MatchRowNbr,
Legs = #BackLegs,
CostingModelID = #MatchFound,
RounderCode = #RounderCode
where RowNbr = #CurrRowNbr
update #RouteLegs
set MatchedRowNbr = #CurrRowNbr,
Legs = #FrontLegs,
CostingModelID = #MatchFound,
RounderCode = #RounderCode
where RowNbr = #MatchRowNbr
--select * from #RouteLegs
--print 'back haul updated'
end
end
end
fetch next from csrFindMatch
into #MatchRouteID, #MatchRowNbr, #MatchTripDate
end
close csrFindMatch
deallocate csrFindMatch
end
fetch next from csrRouteLeg
into #CurrRouteID, #CurrRowNbr, #CurrTripDate, #CurrWaybillNbr
end
fetch next from csrRouteLeg
into #CurrRouteID, #CurrRowNbr, #CurrTripDate, #CurrWaybillNbr
end
close csrRouteLeg
deallocate csrRouteLeg

Invalid column name '#Results'

alter PROCEDURE sp_Get_CustInfoSerach2
(#PageIndex INT = 1
,#PageSize INT = 10
,#RecordCount INT OUTPUT
,#ColumnName VARCHAR(50)=null
,#Value VARCHAR(50)=null
,#ddlValue VARCHAR(50)=null
,#txtValue VARCHAR(50)=null
,#status varchar(30))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cmd AS NVARCHAR(max)
if #txtValue IS NULL
Begin
SET #Value = ''''+#ddlValue+ ''''
End
else if #ddlValue IS NULL
begin
SET #Value = ''''+#txtValue+ ''''
end
SET #cmd = 'SELECT ROW_NUMBER() OVER
(
ORDER BY C_Register.UserId desc
)AS RowNumber
,C_Register.UserId, C_Register.Name, C_Register.UserName, C_Register.Status,
Packages.PackagePeriod, Packages.PackageName, C_Register.ActivationDate,
Receive_Payment.OldExpiryDate, Receive_Payment.Balance, Receive_Payment.PyingAmount,
Receive_Payment.LastPaidDate, C_Register.LastUpdateTime,
Area.AreaName, C_Register.MobNo, Employee.EmpName, C_Register.Address,C_Register.CreatedDate
INTO'+ #Results+'
FROM C_Register INNER JOIN Receive_Payment ON C_Register.UserId = Receive_Payment.UserId
INNER JOIN Area ON C_Register.AreaId = Area.AreaId
INNER JOIN Employee ON Receive_Payment.EmpId = Employee.EmpId
INNER JOIN Packages ON Receive_Payment.PackageId = Packages.PackageId
where C_Register.AccountExpiry= Receive_Payment.OldExpiryDate And C_Register.Status = '+#status+'And
' + #ColumnName + ' = ' + #Value
SELECT #RecordCount = COUNT(*)
FROM #Results
SELECT * FROM #Results
WHERE RowNumber BETWEEN(#PageIndex -1) * #PageSize + 1 AND(((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results
EXEC(#cmd)
END
throwing error:
Invalid column name '#Results'.
how to solve it?
If i understand your problem correctly you should first exec dynamic sql before select from temporary table
Alter PROCEDURE sp_Get_CustInfoSerach2
(
#PageIndex INT = 1 ,
#PageSize INT = 10 ,
#RecordCount INT OUTPUT ,
#ColumnName VARCHAR(50)=null ,
#Value VARCHAR(50)=null ,
#ddlValue VARCHAR(50)=null ,
#txtValue VARCHAR(50)=null ,
#status varchar(30)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cmd AS NVARCHAR(max)
If #txtValue IS NULL
Begin
SET #Value = ''''+#ddlValue+ ''''
End
Else
if #ddlValue IS NULL
Begin
SET #Value = ''''+#txtValue+ ''''
End
SET #cmd = 'SELECT ROW_NUMBER() OVER ( ORDER BY C_Register.UserId desc )AS RowNumber,
C_Register.UserId, C_Register.Name, C_Register.UserName, C_Register.Status,
Packages.PackagePeriod, Packages.PackageName, C_Register.ActivationDate,
Receive_Payment.OldExpiryDate, Receive_Payment.Balance, Receive_Payment.PyingAmount,
Receive_Payment.LastPaidDate, C_Register.LastUpdateTime,
Area.AreaName, C_Register.MobNo, Employee.EmpName, C_Register.Address,C_Register.CreatedDate
INTO #Results
FROM C_Register INNER JOIN Receive_Payment ON C_Register.UserId = Receive_Payment.UserId
INNER JOIN Area ON C_Register.AreaId = Area.AreaId
INNER JOIN Employee ON Receive_Payment.EmpId = Employee.EmpId
INNER JOIN Packages ON Receive_Payment.PackageId = Packages.PackageId
where C_Register.AccountExpiry= Receive_Payment.OldExpiryDate And C_Register.Status = '+#status+'And
' + #ColumnName + ' = ' + #Value
/*First Execute above dynamic Sql query */
EXEC(#cmd)
/* From the above execute statemnet the query will executed and temporary table will created on the fly */
SELECT #RecordCount = COUNT(*)
FROM #Results
SELECT * FROM #Results
WHERE RowNumber BETWEEN(#PageIndex -1) * #PageSize + 1 AND(((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results
Problem in your query is creation of temp table thats not right way to create temp table inside dynamic query.
But even if you create temp table inside a dynamic query it can be accessed only inside the session of dynamic query. If you try to select the temp outside of dynamic query which is created inside the dynamic query you will get a error saying object doesnot exist.
Since you know the number of columns present in the result of dynamic query you can create the temp table outside of dynamic query and insert the records through dynamic query.
Try changing your procedure like this.
ALTER PROCEDURE Sp_get_custinfoserach2 (#PageIndex INT = 1,
#PageSize INT = 10,
#RecordCount INT output,
#ColumnName VARCHAR(50)=NULL,
#Value VARCHAR(50)=NULL,
#ddlValue VARCHAR(50)=NULL,
#txtValue VARCHAR(50)=NULL,
#status VARCHAR(30))
AS
BEGIN
SET nocount ON;
DECLARE #cmd AS NVARCHAR(max)
IF #txtValue IS NULL
BEGIN
SET #Value = '''' + #ddlValue + ''''
END
ELSE IF #ddlValue IS NULL
BEGIN
SET #Value = '''' + #txtValue + ''''
END
/*create a temp as same structure of your dynamic query select statement*/
CREATE TABLE #result
(
rownum INT,
userid INT,
NAME VARCHAR(100),
username VARCHAR(100),
status VARCHAR(15),
packageperiod VARCHAR(15),
packagename VARCHAR(100),
activationdate DATETIME,
oldexpirydate DATETIME,
balance NUMERIC(22, 4),
pyingamount NUMERIC(22, 4),
lastpaiddate DATETIME,
lastupdatetime DATETIME,
areaname VARCHAR(100),
mobno INT,
empname VARCHAR(100),
address VARCHAR(5000),
createddate DATETIME
)
SET #cmd =
' Insert into #result
SELECT ROW_NUMBER() OVER (ORDER BY C_Register.UserId desc )AS RowNumber,
C_Register.UserId, C_Register.Name, C_Register.UserName,
C_Register.Status, Packages.PackagePeriod, Packages.PackageName,
C_Register.ActivationDate,Receive_Payment.OldExpiryDate,
Receive_Payment.Balance, Receive_Payment.PyingAmount,
Receive_Payment.LastPaidDate, C_Register.LastUpdateTime,
Area.AreaName, C_Register.MobNo, Employee.EmpName,
C_Register.Address,C_Register.CreatedDate
FROM C_Register
INNER JOIN Receive_Payment
ON C_Register.UserId = Receive_Payment.UserId
INNER JOIN Area
ON C_Register.AreaId = Area.AreaId
INNER JOIN Employee
ON Receive_Payment.EmpId = Employee.EmpId
INNER JOIN Packages
ON Receive_Payment.PackageId = Packages.PackageId
where C_Register.AccountExpiry= Receive_Payment.OldExpiryDate And C_Register.Status = ' + #status + ' And ' + #ColumnName + ' = ' + #Value
SELECT #RecordCount = Count(*)
FROM #results
SELECT *
FROM #results
WHERE rownumber BETWEEN( #PageIndex - 1 ) * #PageSize + 1 AND( (
( #PageIndex - 1 ) * #PageSize + 1 ) +
#PageSize ) - 1
DROP TABLE #results
EXEC(#cmd)
END
Note : I have given generic datatypes to temp table columns please change the datetypes according to your schema.

Resources