Missing expression Oracle Query - sql

I have a oracle trigger and it returns the error
Additional information: ORA-00936: missing expression
In my TOAD it shows me the below line.
EXECUTE IMMEDIATE 'UPDATE TBL_NEWS_TYPE SET FULLNAME='|| newsName ||' WHERE ID = SELECT MAX(ID) FROM TBL_NEWS_TYPE)';
In here newsName is varchar2 variable like newsName VARCHAR2(50) / and ID in INTEGER.

Try this:
EXECUTE IMMEDIATE 'UPDATE TBL_NEWS_TYPE
SET FULLNAME='''|| newsName
||''' WHERE ID = (SELECT MAX(ID) FROM TBL_NEWS_TYPE)'
I think you had two problems here:
1) You were missing '(' at the start of the select
2) I think this won't work without putting quote sign wraping the newsName because its a string.

Related

How do I reuse a variable as a table name in select query

I need to get an id from a table, whose table name is defined by running another query.
I tried to implement it by defining a variable that saves the results from the first query. Then I created a second query that consumes the table name from the first one.
define tablename = (SELECT table_name FROM tables_names WHERE row_id = 147);
define rowid = SELECT row_id FROM &tablename WHERE title is NULL;
select * from &rowid;
However it doesn't work. I also tried to create a stored procedure, but I don't understand how it should work either:
DECLARE
tablename varchar(128);
rowid int;
BEGIN
SELECT table_name INTO tablename FROM tables_names WHERE row_id = 147);
SELECT row_id INTO rowid FROM &tablename WHERE title is NULL;
END;
The output should give me the expected rowid. I'm not an Oracle expert and this seems like a simple thing, but I don't know how to achieve it.
Use execute immediate as following:
DECLARE
rowid_ int; -- dont use oracle reserved words as variable name.
-- added _ after rowid
BEGIN
EXECUTE IMMEDIATE 'SELECT row_id FROM '
|| (SELECT table_name FROM tables_names WHERE row_id = 147)
|| ' WHERE title is NULL' INTO ROWID_;
-- do something with rowid_ or other logic
END;
/
Cheers!!
This is called dynamic sql.
Edit the procedure and have it do
EXECUTE IMMEDIATE
"SELECT row_id INTO :x FROM " || tablename || " WHERE title IS NULL"
USING rowid;
This is from memory so it might not work, but should give you a good start on how to do it

Use variable inside "from" in firebird

I try use variable inside "from" SELECT COUNT(*) FROM :T_NAME, but is not work. How can i fix this? This my code:
SET TERM ^ ;
CREATE OR ALTER PROCEDURE Myfunction
RETURNS(
T_NAME varchar(100),
NUM_RECORDS integer
)
AS
BEGIN
FOR SELECT RDB$RELATION_NAME FROM RDB$RELATIONS
WHERE (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND RDB$VIEW_BLR IS NULL
ORDER BY RDB$RELATION_NAME
INTO :T_NAME
DO
BEGIN
SELECT COUNT(*) FROM :T_NAME
INTO :NUM_RECORDS;
SUSPEND;
END
END^
SET TERM ; ^
You can't parametrize object names. You will need to dynamically build the query (which if you aren't careful may leave you open to SQL injection).
Specifically you need to use:
...
BEGIN
EXECUTE STATEMENT 'select count(*) from "' || T_NAME || '"'
INTO :NUM_RECORDS;
SUSPEND;
END
This should be safe except for table names that contain double quotes. I haven't explicitly checked the behavior with single quotes in an object name, which technically is possible. You may need to take extra steps to protect against these forms of SQL injection if you use this in real production code.

Find tables, columns with specific value

I'm using Firebird 2.5.0. I know a value and need to find all tables, columns in which it occurs.
I created procedure:
CREATE OR ALTER PROCEDURE NEW_PROCEDURE (
searching_value varchar(30))
returns (
table_with_value varchar(100),
column_with_value varchar(100))
as
declare variable all_tables varchar(50);
declare variable all_columns varchar(50);
declare variable all_values varchar(50);
begin
FOR SELECT
r.rdb$relation_name, f.rdb$field_name
from rdb$relation_fields f
join rdb$relations r on f.rdb$relation_name = r.rdb$relation_name
and r.rdb$view_blr is null
and (r.rdb$system_flag is null or r.rdb$system_flag = 0)
order by 1, f.rdb$field_position INTO :all_tables, :all_columns
DO
BEGIN
FOR SELECT all_columns FROM all_tables
INTO :all_Values
DO
BEGIN
IF (SEARCHING_VALUE = all_Values) THEN
BEGIN
table_With_Value = all_Tables;
column_With_Value = all_Columns;
SUSPEND;
END
END
END
END^
When I run it I get error message:
Undefined name.
Dynamic SQL Error.
SQL error code = -204.
Table unknown.
ALL_TABLES.
At line 21, column 13.
So in this select statement "SELECT all_columns FROM all_tables" it is not taking values from previous for select statement but just trying to find table all_tables. How to fix it?
The problem is that all_columns is considered to be a colum name and all_tables a table name and not your variables in:
SELECT all_columns FROM all_tables
You can't parametrize objectnames in a query like this. Also note that if it had been possible to parametrize object names, you would have had to use :all_columns and :all_tables for disambiguation.
Instead you will need to create a dynamic SQL statement and execute that with EXECUTE STATEMENT (or more specifically: FOR EXECUTE STATEMENT).
In this case:
FOR EXECUTE STATEMENT 'SELECT "' || all_columns || '" FROM "' || all_tables || '"'
INTO :all_values
DO
BEGIN
/* .... */
END
I have quoted the object names to account for case sensitive column and table names (or identifiers that are invalid unquoted). Constructing a query like this might leave you open to SQL injection if the values are obtained from another source than the Firebird metadata tables.

Oracle merge statement within procedure fails to recognize variable in using clause [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
UPSERT into table with dynamic table name
The following procedure is declared as so:
CREATE OR REPLACE
PROCEDURE STUFF(tableToQuery VARCHAR2) AS
BEGIN
MERGE INTO myTable m
USING (select * from tableToQuery) t
ON (m.id = t.id)
... --other stuff
END STUFF;
I receive an ORA-00903 error that states the table name is invalid. My question is how do I get the value that resides within tableToQuery to equate to a valid table name in the select statement? Assume that I do not know the table name ahead of time.
UPDATE
The function compiles now, however I currently receive the unknown keyword error at the end of my function.
You need to use dynamic SQL: ie construct your SQL statement in a string and then pass that string to Oracle to execute using the execute immediate statement.
Something like
CREATE OR REPLACE
PROCEDURE STUFF(tableToQuery IN VARCHAR2) AS
s varchar2(100);
BEGIN
s := 'MERGE INTO myTable m'
|| ' USING (select * from ' || tableToQuery || ') t'
|| ' ON (m.id = t.id)';
EXECUTE IMMEDIATE s;
--other stuff
END STUFF;
should do the trick for you.
NB don't pass unverified data from end users (especially ones on the web) in the parameter tableToQuery as then you will have a SQL injection vulnerability!

Oracle SQL: variables used in place of table names

I am converting a MSSQL script to Oracle, and I haven't been able to figure out the syntax to use a variable in place of a table name or column.
Here is a simple example that I've been try to make work in Oracle SQL Developer so I can better understand the syntax:
set serveroutput on format wrapped;
declare
VR_TABLE VARCHAR2(256);
VR_UPDATE VARCHAR2(256);
begin
VR_TABLE :='SYSTEM_STATUS';
EXECUTE IMMEDIATE 'select UPDATE_VERSION INTO VR_UPDATE from ' || VR_TABLE || 'where rownum < 2 ;'
end;
Where VR_TABLE is the variable table name that will get changed each iteration of the loop.
Can somebody point out what I'm doing wrong, or link me to a site that would be useful for me to read? I've read a few tutorials on this, but I haven't had any luck thus far.
You need to have a space between the table name and the subsequent WHERE clause
The INTO needs to be part of the EXECUTE IMMEDIATE, not part of the dynamic SQL statement.
The dynamic SQL statement should not have a trailing semicolon
The EXECUTE IMMEDIATE statement should end with a semicolon
Putting those together, something like this should work
declare
VR_TABLE VARCHAR2(256);
VR_UPDATE VARCHAR2(256);
begin
VR_TABLE :='SYSTEM_STATUS';
EXECUTE IMMEDIATE 'select UPDATE_VERSION from ' || VR_TABLE || ' where rownum < 2'
INTO VR_UPDATE;
end;
Of course, since you're not doing anything with VR_UPDATE, nothing will be displayed when this anonymous block is executed.
INTO part of the query should not be directly included in the query
string.
Syntax
EXECUTE IMMEDIATE(<SQL>)
[INTO<variable>]
[USING <bind_variable_value>]
The above syntax shows EXECUTE IMMEDIATE command.
Clause INTO is optional and used only if the dynamic SQL contains a select statement that fetches values. The variable type should match with the variable type of the select statement.
Clause USING is optional and used only if the dynamic SQL contains any bind variable.
https://www.guru99.com/dynamic-sql-pl-sql.html#2
You can visit this site for a better understanding of Dynamic SQL.