Can't declare variable in Firebird 2.5, why? - variables

I have a one line query:
DECLARE VARIABLE var_SecondsOfTime INTEGER;
But after running the query I am getting this message:
Engine Error (code = 335544569):
Dynamic SQL Error. SQL error code =
-104. Token unknown - line 1, column 9. VARIABLE.
SQL Error (code = -104): Invalid
token.
I've looked everywhere on the Internet and all examples showing the same declaration style which I am using.
What is wrong?

Firebird 2.5 supports execution of code blocks surrounded by a execute block statement, try this:
set term ^ ;
EXECUTE BLOCK
AS
DECLARE VARIABLE var_SecondsOfTime INTEGER;
BEGIN
SELECT 1 from RDB$DATABASE into var_SecondsOfTime ;
END
^
set term ; ^
I issued the select because I'm pretty sure it is not possible to execute an empty block, try this by yourself removing the select.
Edit
My original select was invalid for a block, I added the into clause to collect the result. I never used firebird maestro, but it now works perfectly on isql, as shown.

Try this:
set term ^ ;
EXECUTE BLOCK
AS
DECLARE VARIABLE var_SecondsOfTime INTEGER;
BEGIN
SELECT 1 from RDB$DATABASE into :var_SecondsOfTime ;
END^
set term ;^
The second set term needs the semi colon before the carat.

Related

Declaring variables and select statement in a procedure

I'm writing a SQL procedure which should use calculated date stored as a local variable in a select statement. I'm using Oracle SQL developer. My code is:
create or replace PROCEDURE
my_procedure
AS
BEGIN
DECLARE
l_max_dt DATE;
BEGIN
SELECT MAX(TRX_DT)
INTO l_max_dt
FROM TABLE
WHERE 1=1;
end;
select * from TABLE where trx_dt = l_max_dt;
end;
This code gives me an error : " Error(14,48): PL/SQL: ORA-00904: "L_MAX_DT": invalid identifier" when select statement is present.
How can I store variables to use them in statements?
This is how you write a Procedure. Syntax is incorrect. Read about syntax Here
CREATE OR REPLACE PROCEDURE my_procedure
AS
l_max_dt DATE;
v_var TABLE2%ROWTYPE;
BEGIN
SELECT MAX (TRX_DT)
INTO l_max_dt
FROM TABLE1
WHERE 1 = 1;
-- Assuming the query will retrun only 1 row.
SELECT *
INTO v_var
FROM TABLE2
WHERE trx_dt = l_max_dt;
END;
Your issue is one of scope. In your procedure, you have a nested block, in which you declare the l_max_dt variable. Once the code has exited that block, the l_max_dt variable is no longer in scope - i.e. the outer block does not know anything about it.
There is no need to have a nested block in this instance - you can do it all in the same block, like so:
create or replace PROCEDURE my_procedure
AS
l_max_dt DATE;
BEGIN
SELECT MAX(TRX_DT)
INTO l_max_dt
FROM TABLE
WHERE 1=1;
-- commented out as this isn't valid syntax; there is a missing INTO clause
-- select *
-- from TABLE where trx_dt = l_max_dt;
END my_procedure;
However, you could simply do the query in one fell swoop - e.g.:
select *
from your_table
where trx_dt = (select max(trx_dt) from your_table);
A couple of points about your procedure:
In PL/SQL, if you use an implicit cursor (i.e. when you put a select statement directly in the body of the code) you need to have something to put the results into. You could bulk collect the results into an array, or you could ensure that you will receive exactly one row (or code error handling for NO_DATA_FOUND and TOO_MANY_ROWS) into a record or corresponding scalar variables.
You shouldn't use select * in your procedure - instead, you should explicitly state the columns being returned, because someone adding a column to that table could cause your procedure to error. There are exceptions to this "rule", but explicitly stating the columns is a good habit to get into.

Can't execute sql file

I'm trying to execute the following code using isql:
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'SFPTB051_ABERTURARCLH'))
BEGIN
SELECT * FROM SFPTB051_ABERTURARCLH;
END
The way i'm doing:
isql -i sql_scripts/test.sql _input/mygdb.GDB -user SYSADM -pass masterkey
Output:
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 1, column 1
-IF
At line 1 in file sql_scripts/test.sql
Expected end of statement, encountered EOF
Any ideias?
Thanks!
UPDATE ---
I'm trying the following:
SET TERM # ;
EXECUTE BLOCK AS
BEGIN
SELECT * FROM SFPTB051_ABERTURARCLH
END#
SET TERM ; #
But it's returning:
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 4, column 1
-END
Usually, select statements within a block statement need to return their values. For example, you can return them into variables or return values, which are almost the same.
Furthermore, every statement within a block statement has to be terminated by a semi-colon (;).
Your block statement could look something like this:
SET TERM # ;
EXECUTE BLOCK AS
DECLARE VARIABLE FIELD1 TYPE OF COLUMN SFPTB051_ABERTURARCLH.FIELD1;
/* declare more variables as needed */
BEGIN
FOR
SELECT FIELD1
FROM SFPTB051_ABERTURARCLH
INTO :FIELD1
DO
BEGIN
/* do something with the variables values */
END
END#
SET TERM ; #

How to use TQuery with Oracle SQL syntax for variable assignments and Params?

In a regular Query on Oracle SQL we could use:
var_user VARCHAR2(256) := 'eduard'
select * from a_table where user_name = var_user
If I use this code in Delphi's TQuery.SQL.Text I get the error Incorrect Token Followed By ":"..
I believe it is happening because Delphi uses : symbol in this case to specify a parameter inside TQuery.SQL.Text to be replaced by the values set at TQuery.Params[].
What I really want to do is SomeVarInsideSQL := :MyParam and I can't because of that error. What should I do? (delphi-xe3-zeoslib)
You need to escape : to :: if you have to bypass specific TQuery Parameter parsing.

ORACLE PL/SQL Variable Function Scope - Need Explanation

I just tripped over an answer to a problem I was having with a PL/SQL variable not being recognized by a function and I was hoping someone could explain to me why my solution worked and what is happening "underneath the hood".
Background
As part of an optimization project, I am trying to collect metrics on individual SQL scripts within a Stored Procedure. The Stored Proc that I am dissecting has an In-type date parameter that I need to define in order to run each individual SQL Script:
CREATE OR REPLACE myStoredProc (DATE_IN DATE, ERROR_OUT OUT VARCHAR2)
IS
BEGIN
--Truncate Temp Tables
--6 Individual SQL Scripts
EXCEPTION
--Error Handling
END;
To run each script individually, I decided to just drop each SQL statement into a PL/SQL block and feed the DATE_IN parameter in as a variable:
DECLARE
DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
--Place individual script here
END;
The Problem
This approach worked fine for a couple of the queries that referred to this DATE_IN variable but one query with a reference to an outside function which takes DATE_IN as a parameter started throwing an ORA-00904 error:
DECLARE
DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
insert into temp_table
SELECT table1.field1,
table1.field2,
table2.fieldA,
MyFunction(table1.field1, DATE_IN) --This was the problem line
FROM
table1,
table2
WHERE EXISTS (inner query)
AND table1.keys = table2.keys
AND table2.date <= DATE_IN
END;
Solution
At the advice of another Developer, I was able to get around this error by adding a colon (:) in front of the DATE_IN variable that I was passing into the function so that the problem line read MyFunction(table1.field1, :DATE_IN). As soon as I did that, my error disappeared and I was able to run the query without issue.
I was happy for the result but the other Developer wasn't able to explain why it was needed, only that it was necessary to call any functions or other stored procs from a PL/SQL statement. I assume this has something to do with scope but I would like to get a better explanation as to why this colon was necessary for the function to see the variable.
Questions
I've tried to do a little research looking over Oracle documentation on parameters, variables, binding/declaring and constants but my research has only given me more questions:
After reading up on variables, I now question if that is the correct term for what I have been using (since I didn't actually use the VARIABLE command and I'm passing in a date - which is not an allowable data type). If my DATE_IN DATE := statement is not a variable, then what is it?
Why were the rest of my references to DATE_IN recognized by the compiler but passing the value to the function was out of scope?
What exactly is the colon (:) doing here? Is this turning that into a bind variable?
Thanks in advance. I appreciate any guidance you can provide!
----------------------------------EDIT--------------------------------------
I was asked to provide additional information. My Db version is 11G, 11.2.0.2.0. The query that I was able to reproduce this error is below.
DECLARE
EXTRACT_DT_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
--This begins the pre-optimized query that I'm testing
insert into AELI_COV_TMP_2_OPT
SELECT /*+ ordered use_nl(CM MAMT) INDEX (CM CSMB_CSMB2_UK) INDEX (MAMT (MBAM_CSMB_FK_I) */
CM.CASE_MBR_KEY
,CM.pyrl_no
,MAMT.AMT
,MAMT.FREQ_CD
,MAMT.HOURS
,aeli$cov_pdtodt(CM.CASE_MBR_KEY, EXTRACT_DT_IN)
FROM
CASE_MEMBERS CM
,MEMBER_AMOUNTS MAMT
WHERE EXISTS (select /*+ INDEX(SDEF SLRY_BCAT_FK_I) */
'x'
from SALARY_DEF SDEF
where SDEF.CASE_KEY = CM.CASE_KEY
AND SDEF.TYP_CD = '04'
AND SDEF.SLRY_KEY = MAMT.SLRY_KEY)
AND CM.CASE_MBR_KEY = MAMT.CASE_MBR_KEY
AND MAMT.STAT_CD = '00'
AND (MAMT.xpir_dt is null or MAMT.xpir_dt > EXTRACT_DT_IN)
AND MAMT.eff_dt <= EXTRACT_DT_IN;
--This ends the pre-optimized query that I'm testing
END;
Here is the error I'm encountering when trying to run an Explain Plan on this statement. I am able to get past this error if I remove reference to line 13 or I add a colon (:) to the EXTRACT_DT_IN on that line.
----------------------EDIT 2-------------------
Here is the function signature of aeli$.cov_pdtodt. (I've replaced the owner for security reasons).
CREATE OR REPLACE function __owner__.aeli$cov_pdtodt
(CASE_MBR_KEY_IN IN NUMBER, EXTRACT_EFF_DT_IN DATE)
RETURN DATE IS
PDTODT DATE;
Your anonymous block is fine as it is, as long as you execute the whole block. If you try to execute just the insert, or its select, as a standalone command then it will indeed fail with ORA-00904.
That isn't quite a scope problem, it's a context problem. You're trying to refer to a PL/SQL variable in an SQL context, and that is never going to work.
In a PL/SQL context this would work:
declare
some_var dual.dummy%type := 'X';
begin
insert into some_table
select dummy from dual where dummy = some_var;
end;
/
... because the insert has access to the PL/SQL some_var.
In an SQL context this will error:
select * from dual where dummy = some_var;
... because it's looking for a column called SOME_VAR, and there isn't one.
If you do this instead:
select * from dual where dummy = :some_var;
... the some_var is now a client-managed bind variable. If you execute that you'll either be prompted for the bind value, or given a not-all-variables-bound error, or bind-variable-not-declared, or similar, depending on your client.
If you only do an explain plan of that though, e.g. with
set auto trace traceonly explain
select * from dual where dummy = :some_var;
... then the bind variable doesn't necessarily have to be populated for the plan to be calculated. Some clients may still complain and want a bind value, but the parser would be OK with it - enough to produce a plan anyway. Though not able to take advantage of bind variable peeking or histograms etc.
For example, SQL Developer happily produces a plan for your original sample query if both references are turned into bind variables, just the insert ... part of the block is selected, and you press Explain Plan (F10).
I'm not sure what you read, but you're mixed up on a few things here.
Your DATE_IN is a variable. You don't need to type 'VARIABLE' anywhere to declare a variable, all you need is the name of the variable and the datatype.
All of the below are legitimate variables in PL/SQL (although poorly named).
variable_1 NUMBER;
variable_2 VARCHAR2(100);
variable_3 DATE;
It's hard to tell what you're doing in your code without seeing it all. Do you have two DATE_IN variables declared within the same block? Is DATE_IN the name of a column in your table?
If you have a column named DATE_IN in table1 or table2, that's likely your problem. Oracle doesn't know if you want to use your variable or your column, and it will always default to the column name. Your function would be expecting a DATE and receiving a column, hence the error.

How do you assign a sequence value to a variable?

I need to assign a sequence value to a variable for use later after the sequence value has been incremented. I've tried this but it gives an error:
variable imageID number;
select SEQ_IMAGE_ID.CURRVAL into :imageID from dual;
select * from IMAGES where IMAGE_ID = :imageID;
Error starting at line 2 in command:
select SEQ_IMAGE_ID.CURRVAL into :imageID from dual
Error report:
SQL Error: ORA-01006: bind variable does not exist
01006. 00000 - "bind variable does not exist"
I have triple checked that the sequence name is correct, any ideas?
You seem to be doing this in SQL*Plus or SQL Developer, from the variable declaration. You need to do the assignment in a PL/SQL block, either with an explicit begin/end or with the exec call that hides that:
variable imageID number;
exec select SEQ_IMAGE_ID.CURRVAL into :imageID from dual;
select * from IMAGES where IMAGE_ID = :imageID;
If you're using 11g you don't need to select, you can just assign:
variable imageID number;
exec :image_id := SEQ_IMAGE_ID.CURRVAL;
select * from IMAGES where IMAGE_ID = :imageID;
You could also use a substitution variable:
column tmp_imageid new_value image_id;
select SEQ_IMAGE_ID.CURRVAL as tmp_imageID from dual;
select * from IMAGES where IMAGE_ID = &imageID;
Note the change from : to indicate a bind variable, to & to indicate a substitution variable.
In PL/SQL, the variable needs to be declared, something like this:
declare
V_IMAGEID;
begin
select SEQ_IMAGE_ID.CURRVAL into V_IMAGEID from dual;
select * /*into ... */ from IMAGES where IMAGE_ID = V_IMAGEID;
end;
If you're using bind variables, the variable must be bound. The error message indicates this isn't the case. How exactly to bind variables depends on the language/situation. Make sure you use the right direction when binding variables. In the first (dual) query, you will need an out parameter. You may need to specify this.
just remove ':' before :imageId. If you are in a trigger use :new.imageid
the word variable should be removed as well
p.s. I mean anonymous block surely.