SQLRPGLE syntax for Exec sql from a varying length variable? - sql

On IBMi (database is DB2 for i) in SQLRPGLE I have a program that builds a large SQL statement into a variable that I would like to run.
When I try to run it as a variable I receive a token error
Some background
Here is an example that works because it does not use a variable
Exec SQL
Create table MyLib/MyFile as(select * from XXLIB/XXFILE)
DATA INITIALLY DEFERRED REFRESH DEFERRED
maintained by user;
When I save this in a variable like #SQLStm and then try to execute as SQL
Exec SQL
:#SQLStm;
I get the error
Token : was not valid. Valid tokens: .
Also I am open to different approaches
https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/cl/runsqlstm.htm
Like RUNSQLSTM SRCFILE(MYLIB/MYFILE) SRCMBR(MYMBR)
Maybe there is a way to take a variable and save it to a source member?
Then use RUNSQLSTM over the source member
Showing some code:
Definition for the variable
d #SQLStm s A Len(6144) Varying(4)
Even when trying a portion of the SQL statement as a variable
#SQLStm = select * from XXLIB/XXFILE;
and then try:
Exec SQL
Create table MyLib/MyFile as( :#SQLStm)
DATA INITIALLY DEFERRED REFRESH DEFERRED
maintained by user;
I get the error
Token : was not valid. Valid tokens: .
I expect the SQLRPLE to compile
Instead of SQL precompile failed.
MSG ID SEV RECORD TEXT
SQL0104 30 236 Position 31 Token : was not valid. Valid tokens:
.
Message Summary
Total Info Warning Error Severe Terminal
1 0 0 0 1 0
30 level severity errors found in source

This is static SQL
Exec SQL
Create table MyLib/MyFile as(select * from XXLIB/XXFILE)
DATA INITIALLY DEFERRED REFRESH DEFERRED
maintained by user;
What you want is dynamic SQL
wSqlStmt = 'Create table MyLib/MyFile as(select * from XXLIB/XXFILE)'
+ ' DATA INITIALLY DEFERRED REFRESH DEFERRED'
+ ' maintained by user';
exec SQL
execute immediate :wSqlStmt;
Note that some statements can't be execute immediate instead you have to prepare then execute them.
more information can be found in the Embedded SQL programming manual.

Related

Execute SQL Task Error: Executing the query failed with the following error: "Incorrect syntax near ''."

I am working on a SSIS package that rejects already loaded files & load only new files to table.
I used for each loop and exceute SSQL to validate if the files are already loaded. When I evaluate
the expression of Execute SQL Task, it evaluates fine. But When I run the paackage I get the following error.
[Execute SQL Task] Error: Executing the query "DECLARE #FileName VARCHAR(100)
SET #FileName=Custo..." failed with the following error: "Incorrect syntax near ''.".
Possible failure reasons: Problems with the query, "ResultSet" property not set correctly,
parameters not set correctly, or connection not established correctly.
The Expression I used in the Execute SQL task is :
"DECLARE #FileName VARCHAR(100)
SET #FileName="+#[User::FileName]+"'
IF EXISTS (SELECT 1
FROM [dbo].[FileLoadStatus]
WHERE filename =#FileName)
BEGIN
SELECT 1 AS FileExistsFlg
END
ELSE
BEGIN
Select 0 AS FileExistsFlg
END"
screen shot of the execute SQL Task
I really apprecaite if you can tell where the problem is ?
You could simplify your expression a little bit to make clear where the SSIS variable is being used:
"SELECT COUNT(*) AS FileExistsFlg
FROM (
SELECT TOP(1) *
FROM
dbo.FileLoadStatus
WHERE
[filename] = '" + #[User::FileName] + "'
) x;"
On the other hand for the SQL Task you could use a standard parameterized query. Assuming you are using an OLEDB connection, the parameter placeholder is the ? sign. No expression is needed and the equivalent Direct Input for the task is:
SELECT COUNT(*) AS FileExistsFlg
FROM (
SELECT TOP(1) *
FROM
dbo.FileLoadStatus
WHERE
[filename] = ?
) x;
With OLEDB you have to map your variable to the placeholder by position (zero based) so in this case the Parameter Name is the number zero. The other properties depend on your metadata and correspond to the variable you would have declare in SQL...
This is less error prone, clearer and reusable for multiple calls as it generates a Prepared Statement.
If your connection type was ADO.Net, the mapping is name based. So check the documentation for the Parameter names and markers for each connection type.

SSIS Looping with Return Value from Stored Procedure

I am trying to create a SSIS Package that loops based on the return value of a stored procedure run in the loop. I keep getting a super NOT helpful error of:
"Error: 0xC002F210 at Load Order, Execute SQL Task: Executing the query "EXEC ? = [Load_Focus_OrderNum] ?, 1" failed with the following error:
"Value does not fall within the expected range.".
Possible failure reasons:
Problems with the query, "ResultSet" property not set correctly, parameters not set correctly, or connection not established correctly.
Task failed: Load Order"
Here is my setup:
The Load Order stored procedure loads a table with 500 orders at a time, then the last order number is returned (I have confirmed it returns correctly).
DECLARE #spOut int
EXEC #spOut = Load_Focus_OrderNum 1, 1
PRINT #spOut
Returns 638 as expected
I then want it to process the next 500 starting at the next order.
I'm calling my stored procedure with:
EXEC ? = sp_LoadOrders ?, 1
Procedure snippet:
ALTER PROCEDURE [dbo].[LoadOrders]
(#PK_ID INT, #OrdType INT)
AS
-- Loads OrderNumTbl table
RETURN (SELECT TOP 1 ID FROM OrderNumTbl ORDER BY ID DESC)
GO
My parameter mapping for it is:
And my expressions for the loop are:
What am I missing? Any help is appreciated!
In the parameter Mapping section, replace the parameter name value with the parameter index >> replace #OrderID with 0 and #T1_ID with 1
References
SSIS: Value does not fall within the expected range
SQL Server Central - SSIS: Value does not Fall Within the Expected Range
Parameters and Return Codes in the Execute SQL Task

Pro C dynamic SQL query

I have to execute the following query using Pro C to get the output and den display the output to the user.
i tried the following code snippet:
int count=0;
char query1[100]="select count(code) from customer where customer_type='a';";
EXEC SQL ALLOCATE DESCRIPTOR 'out' ;
EXEC SQL PREPARE statement FROM :query1 ;
EXEC SQL DESCRIBE OUTPUT statement USING DESCRIPTOR 'out' ;
EXEC SQL SET DESCRIPTOR 'out' VALUE 1 TYPE = :data_type,
LENGTH = :data_len, DATA = :count ;
EXEC SQL DECLARE c CURSOR FOR statement ;
EXEC SQL OPEN c ;
EXEC SQL FETCH c INTO DESCRIPTOR 'out' ;
EXEC SQL GET DESCRIPTOR 'out' VALUE 1 :count = DATA;
EXEC SQL CLOSE c ;
printf("%-8d ",count);
but the output i get is always 0.
How shall i proceed to get the proper output??
can anyone help pls...
It is quite possible you have some errors in there that arn't getting noticed.
Use the EXEC SQL WHENEVER to get some error checking going on.
The one thing that jumps out at me is the semicolon at the end of the query1 value. If I recall correctly, Pro*c will barf on it.
I would strongly recommend against using this method of Pro*C dynamic SQL (Oracle dynamic SQL method 4) unless you can possibly avoid it.
The only case you should need to use this method is when you are using dynamically generated SQL and you don't know how many host variables will be used. E.g. You don't know how many columns will be in the SELECT clause.
A fully fledged example of using Oracle dynamic SQL method 4 can be found at http://docs.oracle.com/cd/B28359_01/appdev.111/b28427/pc_15ody.htm#i7419.

Can I use a variable as the value of the option AUDIT_GUID for the CREATE SERVER AUDIT statement?

I am trying to make the Audit_GUID value in the CREATE SERVER AUDIT command dynamic by using the NEWID() function in SQL. Below is my SQL script to do this:
USE [master]
GO
DECLARE #newGUID as uniqueidentifier
SET #newGUID = NEWID()
CREATE SERVER AUDIT Audit_Select_Queries -- Name of the Audit(unique for a Server)
TO FILE
( FILEPATH = N'XXXX' -- Folder to Store Audit Files at
,MAXSIZE = 0 MB -- 0 = UNLIMITED
,MAX_ROLLOVER_FILES = 2147483647 -- Max possible number of Files
,RESERVE_DISK_SPACE = OFF
)
WITH
( QUEUE_DELAY = 1000 -- Delay Audit actions by this time for completion
,ON_FAILURE = CONTINUE -- Database operation is more important than Audit
,AUDIT_GUID = #newGUID -- UUID of the Audit (unique for a server)
)
ALTER SERVER AUDIT Audit_Select_Queries WITH (STATE = OFF)
GO
But I get a syntax error near #newGUID saying "Incorrect syntax near '#newGUID'"
Please let me know what am I doing wrong.
EDIT: I am working on Microsoft SQL Server 2012
No ...
CREATE SERVER AUDIT is a statement – so AUDIT_GUID isn't a 'parameter' in the same way that a SQL Server parameter of a stored procedure is a parameter. If you're familiar with other languages, you could consider CREATE SERVER AUDIT as a 'special form' and, as such, you simply need to remember that it doesn't accept variables for that option.
I can understand why that's confusing as, for example, the BACKUP statement(s) do allow variables for certain 'parameters' ("options"), namely the name of the database; e.g. this is perfectly valid T-SQL:
DECLARE #databaseName nvarchar = "insert_name_of_database_here";
BACKUP DATABASE databaseName
...
For clarifying these types of questions, just consult Microsoft's documentation for the relevant version of SQL Server if you can't remember whether some parameters or options accept variables or not. [You can easily open the relevant documentation from SSMS by highlighting the statement, built-in procedure, etc. and hitting F1 on your keyboard.]
But if You're Willing to Dynamically Generate the T-SQL ...
Here's how you can use dynamic SQL – via EXECUTE or sp_executesql – to do what you're trying to do:
DECLARE #dynamicSql nvarchar(1000);
SELECT #dynamicSql = 'CREATE SERVER AUDIT
...
AUDIT_GUID = ''' + CAST(#newGUID AS nvarchar(255)) + ''''
+ '...' + ...,
EXEC sp_executesql #dynamicSql;

Error SQL0104 when creating a function in System i V7R1

I'm creating a SQL function on System i V7R1:
CREATE FUNCTION MYSCHEMA.GROUPDIBAS(v_code VARCHAR(50))
RETURNS VARCHAR(2048)
LANGUAGE SQL
BEGIN
DECLARE str VARCHAR(2048);
SET str = '';
FOR row AS (
SELECT
FIELD2
FROM MYSCHEMA.DIBAS
WHERE FIELD1 = v_code
)
DO
SET str = 'Bubi'; --I removed many statements to make clear the problem doesn't come from them
END FOR;
RETURN str;
END
;
I execute it with "Run SQL script" tool, which is part of the iSeries Navigator V7R1.
It works on another V7R1 server (using iSeries Navigator V5R4), but not in that one where I'm working now. It fails with this message:
SQL State: 42601
Vendor Code: -104
Message: [SQL0104] Token <END-OF-STATEMENT> was not valid. Valid tokens: ;.
Cause . . . . . : A syntax error was detected at token <END-OF-STATEMENT>.
Token <END-OF-STATEMENT> is not a valid token. A partial list of valid tokens is ;.
This list assumes that the statement is correct up to the token.
The error may be earlier in the statement, but the syntax of the statement appears to be valid up to this point.
Recovery . . . : Do one or more of the following and try the request again:
-- Verify the SQL statement in the area of the token <END-OF-STATEMENT>. Correct the statement.
The error could be a missing comma or quotation mark, it could be a misspelled word, or it could be related to the order of clauses.
-- If the error token is <END-OF-STATEMENT>, correct the SQL statement because it does not end with a valid clause.
If I remove the FOR block, it works.
Moreover if I execute the statement with 5250 Emulator, command STRSQL, it works. So it seems like a bug in "Run SQL script" client.
Any hint will be appreciated!
The issue is with the FOR statement. The query analyzer is inconsistent on when the cursor-name CURSOR FOR is optional and when it is required even though the documentation states if it is not specifified a unique cursor name is generated. SQL submitted via the IBM Access Navigator Run Scripts utility require it.
The parenthesis are also incorrect but sometimes they are accepted (STRSQL, Navigator Run SQL Scripts) and sometimes they aren't (DBVisualizer/JDBC).
TIL there must be a different query analyzer running depending on the source of the query.
CREATE FUNCTION MYSCHEMA.GROUPDIBAS(v_code VARCHAR(50))
RETURNS VARCHAR(2048)
LANGUAGE SQL
BEGIN
DECLARE str VARCHAR(2048);
SET str = '';
FOR row AS C1 CURSOR FOR
SELECT
FIELD2
FROM MYSCHEMA.DIBAS
WHERE FIELD1 = v_code
DO
SET str = 'Bubi'; --I removed many statements to make clear the problem doesn't come from them
END FOR;
RETURN str;
END
Given the tests made by #JamesA and me, I fear the problem can be in the Program Temporary Fix (PTF) that this server hasn't and the other ones have. Specifically, running WRKPTFGRP command, I can guess it probably misses this PTF group:
PTF group Level Text
SF99701 5 DB2 FOR IBM I
Unfortunately I can't try installing it now :(.
In the session properties of your IDE change the Statement Separator field value from ; to | then reconnect your session. then use | instead of ;. this way you can run your statement or procedure or function.
usage example,
CREATE FUNCTION MYSCHEMA.GROUPDIBAS(v_code VARCHAR(50))
RETURNS VARCHAR(2048)
LANGUAGE SQL
BEGIN
DECLARE str VARCHAR(2048);
SET str = '';
FOR row AS C1 CURSOR FOR
SELECT
FIELD2
FROM MYSCHEMA.DIBAS
WHERE FIELD1 = v_code
DO
SET str = 'Bubi'; --I removed many statements to make clear the problem doesn't come from them
END FOR;
RETURN str;
END |