for loop with dynamic table name and execute immediate - sqlplus

in my Procedure there is the following code line
for i in (select schema_name, table_name, restricted_columns
from GRANTED_TABLES_FOR_ROLE
where restricted_columns = 0) loop
execute immediate 'grant select on ' || i.schema_name || '.' || i.table_name || ' to ROLE_NAME';
end loop;
because i want to create the table "GRANTED_TABLES_FOR_ROLE" earlier in my procudere i can't create the procedure without the "GRANTED_TABLES_FOR_ROLE" existing.
is there any way to make the code above dynamic so i can set a variable for the table "GRANTED_TABLES_FOR_ROLE"?
how i can achieve this?
thanks for your help!

I believe this is a case where you will need to use a dynamic cursor:
DECLARE
TYPE trec IS RECORD
(
schema_name VARCHAR2 (30)
, table_name VARCHAR2 (30)
, restricted_columns VARCHAR2 (30)
);
l_rec trec;
l_sqlstment VARCHAR2 (500)
:= q'[SELECT schema_name, table_name, restricted_columns
FROM <<tablename>>
WHERE restricted_columns = 0 ]';
l_cursor SYS_REFCURSOR;
BEGIN
l_sqlstment :=
REPLACE (l_sqlstment, '<<tablename>>', 'granted_tables_for_role');
OPEN l_cursor FOR l_sqlstatement;
LOOP
FETCH l_cursor INTO l_rec;
EXIT WHEN l_cursor%NOTFOUND;
dbms_outout.put_line (l_rec.schema_name);
dbms_outout.put_line (l_rec.table_name);
dbms_outout.put_line (l_rec.restricted_columns);
EXECUTE IMMEDIATE 'grant select on '
|| l_rec.schema_name
|| '.'
|| l_rec.table_name
|| ' to ROLE_NAME';
END LOOP;
END;

Related

2620:Bad character error in stored procedure teradata

Concatenation is working in select statement:
SELECT 'HELLO' || 'WORLD';
is returning HELLOWORLD, but when I try to use it in stored procedure like below:
SET Time_of_Day=TRIM(Hour_of_Day) || ' : ' || TRIM(Minute_of_Hour) || ' : ' || TRIM(Second_of_Minute);
where Hour_of_Day,Minute_of_Hour,Second_of_Minute are variables, I also tried without TRIM:
ERROR:
**CALL FAILED 2620:PROCEDURE_NAME:THE FORMAT OR DATA CONTAINS A BAD CHARACTER**
Casting a string to a time in Teradata requires two-digit hour/minute/second:
SET Time_of_Day=TRIM(Hour_of_Day (FORMAT '99')) || ' : ' ||
TRIM(Minute_of_Hour (FORMAT '99')) || ' : ' ||
TRIM(Second_of_Minute (FORMAT '99'))
But this snippet is probably from the SP question you deleted an hour ago (a few seconds before I could post my answer).
There's no need for running 86400 single-row Inserts, simply create all data in a single Select, e.g.:
SELECT
Row_Number() Over (ORDER BY h,m,s),
Extract(SECOND From t) AS s,
Extract(MINUTE From t) AS m,
Extract(HOUR From t) AS h,
t
FROM
(
SELECT Cast(Begin(pd) AS TIME(0)) AS t
FROM sys_calendar.CALENDAR
WHERE calendar_date = Current_Date
EXPAND ON PERIOD(Cast(Current_Date AS TIMESTAMP(0)), Cast(Current_Date + 1 AS TIMESTAMP(0))) AS pd
) AS dt

OUTPUT variables to sp_executesql

Background: SQL Server 2008 R2
Having issues with the following. Been given a usp to "finish off", author is unavailable. It extracts data from source table, copies to target table of same name + datetime stamp in an archive db then truncates source table. Want to confirm that no errors have occurred & row counts are the same before I truncate source. As I'm using DDL a TRY CATCH combo won't work.
Following code works:
DECLARE #HostName VARCHAR(30) -- Name of server running script
DECLARE #dbName VARCHAR(30) -- Database currently connected to
DECLARE #LogText VARCHAR(255) -- Text to be logged to ArchLog table
DECLARE #NewUTMetaData VARCHAR(255) -- New tablename for UTMetaData
DECLARE #NewOutboundMessagePending VARCHAR(255) -- New tablename for OutboundMessagePending
DECLARE #NewOutboundMessageStatus VARCHAR(255) -- New tablename for OutboundMessageStatus
DECLARE #NewOutboundMessageResult VARCHAR(255) -- New tablename for OutboundMessageResult
DECLARE #NewFileMessageNonSequence VARCHAR(255) -- New tablename for FileMessageNonSequence
DECLARE #NewOutboundMessageRequest VARCHAR(255) -- New tablename for OutboundMessageRequest
DECLARE #NewOutboundMessage VARCHAR(255) -- New tablename for OutboundMessage
DECLARE #SQLQuery NVARCHAR(500)
DECLARE #return_value INT
DECLARE #Err INT = 0
DECLARE #ErrFin INT = 0
DECLARE #SQLCount NVARCHAR(255) = 'SELECT #TargetCountOUT = COUNT(*) FROM '
DECLARE #ParmDefinition nvarchar(50) = N'#TargetCountOUT int OUTPUT';;
DECLARE #SourceCount INT = 0
DECLARE #TargetCount INT = 0
-- Log message that delete is starting
SELECT #HostName = host_name()
SELECT #dbName = db_name()
SELECT #LogText = 'Procedure ArchiveMuleDBMetrix_NEW starting database= ' + #dbname + ' host= ' + #HostName
EXEC xp_logevent 50001, #LogText, 'INFORMATIONAL'
INSERT INTO [MuleDBArch].[dbo].[ArchLog]
([LogEntryDateTime]
,[LogEntry])
VALUES (GETDATE()
,#LogText)
BEGIN
SELECT #NewUTMetaData = (SELECT '[MuleDBArch].[dbo].UTMetaDataA' + convert(varchar(50),GetDate(),112) + replace(convert(varchar, GetDate(),108),':',''))
SET #err = ##error;
SET #SQLQuery = 'select * into ' + #NewUTMetaData + ' from [MuleDB].[dbo].[SASITUTMetaData]'
EXECUTE sp_executesql #SQLQuery
SET #SourceCount = ##ROWCOUNT
SELECT #LogText = 'Rows archived into ' + #NewUTMetaData + ' by Procedure ArchiveMuleDBMetrix_NEW = ' + CAST(#SourceCount as VARCHAR(6))
EXEC xp_logevent 50002, #LogText, 'INFORMATIONAL'
INSERT INTO [MuleDBArch].[dbo].[ArchLog]
([LogEntryDateTime]
,[LogEntry])
VALUES (GETDATE()
,#LogText)
IF #err = 0
BEGIN
SET #sqlcount = #sqlcount + #NewUTMetaData
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCountOUT=#TargetCount OUTPUT;
IF #SourceCount = #TargetCount
TRUNCATE TABLE [MuleDB].[dbo].[SASITUTMetaData]
ELSE
SELECT #LogText = 'Post archive, row counts differ between [MuleDB].[dbo].[SASITUTMetaData] and' + #NewUTMetaData
EXEC xp_logevent 50003, #LogText, 'Error'
Set #errfin = 1
SET #err = 0
END
ELSE
BEGIN
SELECT #LogText = 'Procedure ArchiveMuleDBMetrix_NEW failed archiving into ' + #NewUTMetaData
EXEC xp_logevent 50004, #LogText, 'Error'
Set #errfin = 1
SET #err = 0
END
END
However, if I repeat the block to work on another table (or indeed the same one) query completes with error and I get the message:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '.'.
I think I've narrowed it down to the line:
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCountOUT=#TargetCount OUTPUT;
Any help appreciated
In the below code
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCountOUT=#TargetCount OUTPUT;
You are trying to pass parameter values without specifying the parameter names except the output parameter while calling the stored procedure. Either specify the parameter name for all or none. Try to execute the code as follows
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCount OUTPUT;

Stored procedure not compiling with 'Set'

I have a Stored procedure which I am not able to compile.
CREATE PROCEDURE FINGOODSCH(IN STRDATE DATE,
IN prodln Char(5))
LANGUAGE SQL
RESULT SETS 1
SET OPTION DBGVIEW =*SOURCE
BEGIN
Declare IN_DATE NUMERIC(7,0);
SET IN_DATE = 0;
/* SET IN_DATE = (DECIMAL(CHAR(SUBSTR(CHAR(STRDATE),1,4); */
/* SUBSTR(CHAR(STRDATE),6,2) CONCAT */
/* SUBSTR(CHAR(STRDATE),9,2))) - 19000000) ; */
Declare FinGoodSCH Cursor for
Select TRIM(ORDNO) as OrderNumber,
( '20' || SUBSTR(CHAR(ODUDT),2,2) || '-' ||
SUBSTR(CHAR(ODUDT),4,2) || '-' ||
SUBSTR(CHAR(ODUDT),6,2)) as OrderDueDate,
TRIM(FITEM) as ModelNumber,
TRIM(DPTNO) as ProductionLine
From ORMAST
Where
DPTNO = prodln
OPEN FinGoodSCH ;
END
THe issue is withthe statement 'SET IN_DATE = 0; (I know I can use Default to set it to 0, but thats not what I am looking for)'. If I remove this statement, it will compile. Compilation error is:
SQL0104 30 3 Position 33 Token FINGOODSCH was not valid. Valid
tokens: GLOBAL.
Also, I tried declaring it with decimal but it did not work
You have to do the declarations in SQL before any executable code....
CREATE PROCEDURE FINGOODSCH(IN STRDATE DATE,
IN prodln Char(5))
LANGUAGE SQL
RESULT SETS 1
SET OPTION DBGVIEW =*SOURCE
BEGIN
Declare IN_DATE NUMERIC(7,0);
Declare FinGoodSCH Cursor for
Select TRIM(ORDNO) as OrderNumber,
( '20' || SUBSTR(CHAR(ODUDT),2,2) || '-' ||
SUBSTR(CHAR(ODUDT),4,2) || '-' ||
SUBSTR(CHAR(ODUDT),6,2)) as OrderDueDate,
TRIM(FITEM) as ModelNumber,
TRIM(DPTNO) as ProductionLine
From ORMAST
Where
DPTNO = prodln;
-- Executable code starts here....
SET IN_DATE = (DECIMAL(CHAR(SUBSTR(CHAR(STRDATE),1,4);
SUBSTR(CHAR(STRDATE),6,2) CONCAT
SUBSTR(CHAR(STRDATE),9,2))) - 19000000) ;
OPEN FinGoodSCH ;
END
Note that if you happened to want to use IN_DATE in your cursor, you'd still do it like the above. The value of any variables used in the DECLARE CURSOR statement are not evaluated until the cursor is opened in DB2.

Stored procedere: flexible param for operator on 'IF #recordCount <= #Menge'

I hope someone can me help again, regarding to my solved stored procedure problem
Is there any chance to make the operator ">" flexible?
Right now my stored procedure works very fine and I will get an eMail when the record count is bigger than the param Menge.
The code is this:
#Menge as int = 0,
#recordCount as int = 0,
set #MySQL = 'select #recordCount=count(2) from ' + #MyTable + ' where ' + #MyWhere
exec sp_execute #MySQL, N'#recordCount int OUTPUT', #recordCount=#recordCount OUTPUT
IF #recordCount > #Menge
begin
...
EXEC msdb.dbo.sp_send_dbmail
Now I want to make > flexible to get an e-mail when the record count is smaller than menge
I tried to declare the param but I don't know how to insert it into the if #recordcount > #Menge line :(
#OpInd as char(1) = null
I would call the stored procedure with
exec sp_eMail_Test3
#Menge = 0,
#eMail_TO = 'testuser#test.xx' ,
#eMail_Subject = 'test3 ',
#eMail_Body = 'Hallo, das ist ein Test',
#MyTable ='test' ,
#MyWhere = 'not [sys_completed] is null'
#OpInd = '<'
If I try IF #recordCount + #OpInd + #Menge then I get the error
An expression of non-boolean type specified in a context where a condition is expected, near 'begin'.
Hopefully you understand my Target and can help me.
If necessary I need to build a 2nd stored procedure :( one for "<" and one for ">"
Best regards Ralf
Just change your operand to <>
IF #recordCount <> #Menge
begin
...
EXEC msdb.dbo.sp_send_dbmail
There are only 3 possible operands you want to deal with. >, <, and =. Since you want an email if it's > or if it's < then just send the email when it's not =.
Another way would to repeat your code.
IF (#recordCount > #Menge or #recordCount < #Menge)
begin
...
EXEC msdb.dbo.sp_send_dbmail
If you are trying to make it either > or < then you can use DynamicSQL. Something like...
declare #sql varchar(max)
set #sql =
'IF ' + cast(#recordCount as varchar(16)) + ' ' + #OpInd + ' ' + cast(#Menge as varchar(16)) + '
begin
...
EXEC msdb.dbo.sp_send_dbmail'
EXEC(#sql)

Error handling in Teradata Stored Procedure

I am trying to develop a stored procedure within TERADATA to handle and manage exceptions.
The stored procedure should raise the error to the caller, which is an SSIS Package.
I am trying to illustrate this by creating a stored procedure for illustration only.
I have these tables:
Table_A:
- ID INT
- ITEM_NUM INT
- DESC VARCHAR(20)
- CREATE_DTTM VARCHAR(2O)
Table_B:
- ID INT
- ITEM_NUM INT
- DESC VARCHAR(20)
- CREATE_DTTM VARCHAR(2O)
I have two tables that will be inserting data from two SELECT statements.
REPLACE PROCEDURE csTest2()
SQL SECURITY OWNER
BEGIN
DECLARE varErrorMessage char(256);
DECLARE varSQLState char(5);
DECLARE varReturnCode char(5);
DECLARE varRollbackNeededInd char(1); /* transaction mgt */
SET varRollbackNeededInd = 'N';
SET varReturnCode = '00000';
SET varErrorMessage = '';
BEGIN TRANSACTION;
-- USING A SINGLE HANDLER WITH MULTIPLE STATEMENTS
-- PLANING TO CHANGE ERROR MESSAGE IN EACH STATEMENT.
ins6: BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
H99:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'This message should not be displayed'; --
end H99;
-- IMAGINE THAT I AM GETTING THE VALUES AS INPUT PARAMERS IN THE PROCEDURE
INSERT INTO "Table_A"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '222', 'SOME DESC',CURRENT_TIMESTAMP;
H98:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'This message is displayed, ITEM_NUM invalid characters';
end H98;
-- NOW I AM DOING A SECOND INSERT TO table b WITH INVALID DATA
-- THE VALUE FOR THE ITEM NUMBER CONTAINS ALPHANUMERICE CHARACTERS
INSERT INTO "Table_b"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '333F', 'SOME DESC',CURRENT_TIMESTAMP;
END ins6;
EndTrans: BEGIN
IF varSQLState <> '0' THEN
SET varRollbackNeededInd = 'Y';
SET varReturnCode = '9999';
END IF;
IF varRollbackNeededInd = 'Y' THEN
ROLLBACK; -- ROLLBACK AND SEND ERROR TO CALLER
SIGNAL SQLSTATE 'U0123' SET MESSAGE_TEXT = 'SQlState is - ' || varSQLSTATE || ' - and error is - ' || varErrorMessage;
ELSE
END TRANSACTION; -- COMMIT TRANSACTION
END IF;
END EndTrans;
END;
The problem that I am facing with the above stored procedure is that error message that I get is not the one that I am expecting. Since error is intentionally created in my second statement I am expecting to get: This message is displayed, ITEM_NUM invalid characters but I am getting This message should not be displayed
Now if I modify the PROCEDURE to have multiple handlers, one for each statement, I do get the correct error message, but now since I am intentionally generating the error in the first statement it does not terminate the procedure, it handles the error and sets the proper message but continues to process the next statement which I am not expecting to do this, so how can I terminate this procedure?
REPLACE PROCEDURE csTest2()
SQL SECURITY OWNER
BEGIN
DECLARE varErrorMessage char(256);
DECLARE varSQLState char(5);
DECLARE varReturnCode char(5);
DECLARE varRollbackNeededInd char(1); /* transaction mgt */
SET varRollbackNeededInd = 'N';
SET varReturnCode = '00000';
SET varErrorMessage = '';
BEGIN TRANSACTION;
ins6: BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
H99:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'Error is displayed in this case because ITEM_NUM';
-- ERROR IS PRESENT IN THIS STATEMENT AND SHOULD TERMINATE THE PROCEDURE.
INSERT INTO "Table_A"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '222F', 'SOME DESC',CURRENT_TIMESTAMP;
END ins6;
ins7: BEGIN
H98:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'no error is displayed in this case';
end H98;
-- NO ERROR IS EXPECTED, BUT IT SHOULD NOT REACH HERE SINCE WE HAD ERROR ON FIRST STATEMENT.
INSERT INTO "Table_b"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '333', 'SOME DESC',CURRENT_TIMESTAMP;
END ins7;
EndTrans: BEGIN
IF varSQLState <> '0' THEN
SET varRollbackNeededInd = 'Y';
SET varReturnCode = '9999';
END IF;
IF varRollbackNeededInd = 'Y' THEN
ROLLBACK; -- ROLLBACK AND SEND ERROR TO CALLER
SIGNAL SQLSTATE 'U0123' SET MESSAGE_TEXT = 'SQlState is - ' || varSQLSTATE || ' - and error is - ' || varErrorMessage;
ELSE
END TRANSACTION; -- COMMIT TRANSACTION
END IF;
END EndTrans;
END;

Resources