SQL Use a Variable as tablename - sql

i would like to set the Tablename as Variable
Why: i go from a oracle db to a mysql db via db link and in the mysql db i have some table-names which includes the date- example: data_20121126
here's my statement :
DECLARE
tbname VARCHAR2 (200);
BEGIN
SELECT ab.teste
INTO tbname
FROM (SELECT '"data_'
|| REPLACE (TO_CHAR (SYSDATE - 1, 'yyyy.mm.dd'),
'.',
'')
|| '"#myDB'
AS teste
FROM DUAL) ab;
SELECT * FROM tbname;
END;
could anybody help me please?
thanks in advance

It's not possible with static SQL (and I doubt that creating a new table for every day in your MySQL database is a sensible design approach).
If you really need to do this, you can
use dynamic SQL (EXECUTE IMMEDIATE / OPEN CURSOR FOR ...)
create a synonym once per day, pointing to the current table, and use that synonym in your query

You can't do this without resorting to dynamic SQL:
DECLARE
tbname VARCHAR2 (200) := '"data_'
|| TO_CHAR (SYSDATE - 1, 'yyyymmdd')
|| '"#myDB';
vMyVariable varchar2(10);
BEGIN
execute immediate "SELECT MyColumn
FROM " || tbname into vMyVariable ;
END;
Of course, this version assumes you'll be returning a single column from a single field into a variable. In all likelihood, you'll really want to return a ref cursor to your calling application.

Related

HANA + Is it possible to create a local temp table with dynamic name (name including current time)?

As we do in SQL, is it possible to pass variable on create statement as a table name in HANA?
I'm trying the below code but its throwing an error
CREATE PROCEDURE temp_table()
AS
table_name nvarchar(255);
BEGIN
table_name := '#TMP_TABLE'+ CURRENT_TIMESTAMP;
CREATE LOCAL TEMPORARY COLUMN TABLE :table_name(
SCENARIO varchar(64) NULL,
SCENARIO_CY varchar(64) NULL,
MONTH_NO numeric(4, 0) NULL
);
DROP TABLE :table_name;
END;
Please help me to find out a solution.
What you are looking for is Dynamic SQL. You will need to pass your SQL statement as a string to function EXEC or EXECUTE IMMEDIATE. The timestamp dependent name can be assembled by string concatenation.
In your code above your are using '+' to do string concatenation:
table_name := '#TMP_TABLE'+ CURRENT_TIMESTAMP;
IMHO this does not work on HANA. You should use a double pipe '||' instead:
table_name := '#TMP_TABLE' || CURRENT_TIMESTAMP;

Oracle Function or Query to get data for all DB tables?

I have to get the min and max dates for the data stored in all the database tables and display same along with the table names. I have written below function to do same
CREATE OR REPLACE FUNCTION data_bound(tbl_name IN VARCHAR2) RETURN VARCHAR2
AS
reqdates VARCHAR2;
BEGIN
EXECUTE IMMEDIATE 'SELECT concat(min(rec_date),max(rec_date)) from ' || tbl_name INTO reqdates;
RETURN reqdates;
END;
And I am trying to fetch data using below.
SELECT table_name, data_bound(table_name) FROM user_tables;
But my function does seems to be working, getting multiple errors. Please can you advise what's wrong here and if there's another better approach.
You can use:
CREATE FUNCTION data_bound(
tbl_name IN VARCHAR2
) RETURN VARCHAR2
AS
reqdates VARCHAR2(39);
BEGIN
EXECUTE IMMEDIATE 'SELECT TO_CHAR(min(rec_date), ''YYYY-MM-DD HH24:MI:SS'')
|| ''-'' || TO_CHAR(max(rec_date), ''YYYY-MM-DD HH24:MI:SS'')
FROM ' || DBMS_ASSERT.SIMPLE_SQL_NAME(tbl_name)
INTO reqdates;
RETURN reqdates;
END;
/
Which, if you have the table:
CREATE TABLE table_name (rec_date) AS
SELECT TRUNC(SYSDATE, 'YYYY') FROM DUAL UNION ALL
SELECT SYSDATE FROM DUAL;
Then:
SELECT data_bound('TABLE_NAME') FROM DUAL;
Outputs:
DATA_BOUND('TABLE_NAME')
2022-01-01 00:00:00-2022-04-19 18:57:25
db<>fiddle here
Error 1: data_bound() function is defined. data_retention() function is called
Error 2: tbl_name is taken as input, but not used (t_name is used once)
Error 3: 'from' keyword is missing in the execute immedeate statement
Error 4: 'into' keyword should be placed before 'from tableName'

sql injection - risk with SELECT

I would like to read user query from variable as (:user_query:) and execute it - in Oracle it will be like:
DECLARE
ddl_qry CLOB;
user_query VARCHAR2(20) := 'SELECT 100 FROM dual';
BEGIN
ddl_qry := 'INSERT INTO a (v) VALUES ((SELECT CAST(( ' || user_query || ') AS NUMBER) as COUNTER FROM dual))';
EXECUTE IMMEDIATE ddl_qry;
END;
I need to insert result of user_query to table 'a'.
I don't care if it will fail or sth, but is this safe? :) Is there any option if string user_query with SQL will drop my database or do sth else?
Or sb can construct a query that will drop my database?
If we fix the (many) syntax errors in your PL/SQL block we come to:
DECLARE
ddl_qry CLOB;
user_query VARCHAR2(20) := '1024';
BEGIN
ddl_qry := 'INSERT INTO a (v) VALUES ((SELECT CAST(( :user_query ) AS NUMBER) as COUNTER FROM dual))';
EXECUTE IMMEDIATE ddl_qry USING user_query;
END;
/
It will work and there is not a SQL injection vulnerability as it uses a bind variable :user_query to input the value.
However, that does not mean that it is particularly good as you:
Do not need to use dynamic SQL;
Do not need to select from the DUAL table; and
Do not need to explicitly CAST the input to a NUMBER as, if the column you are inserting into is a NUMBER then, there will be an implicit cast.
So the above code can be simplified to:
DECLARE
user_query VARCHAR2(20) := '1024';
BEGIN
INSERT INTO a (v) VALUES ( user_query );
END;
/
There is still no SQL injection vulnerability and the query is much simpler.
db<>fiddle here
Update
in Oracle it will be like:
DECLARE
ddl_qry CLOB;
user_query VARCHAR2(20) := 'SELECT 100 FROM dual';
BEGIN
ddl_qry := 'INSERT INTO a (v) VALUES ((SELECT CAST(( ' || user_query || ') AS NUMBER) as COUNTER FROM dual))';
EXECUTE IMMEDIATE ddl_qry;
END;
That has huge SQL injection vulnerabilities.
If user_query is, instead, set to:
SELECT CASE
WHEN EXISTS(
SELECT 1
FROM users
WHERE username = 'Admin'
AND password_hash = STANDARD_HASH( 'my$ecretPassw0rd', 'SHA256' )
)
THEN 100
ELSE 0
END
FROM DUAL
If you get the value 100 then you know that:
There is a table called users;
It has columns username and password_hash;
There is an Admin user; and
You've verified their password.
Please don't use dynamic SQL and string concatenation if you do not need to.

Oracle variable from select statement is empty value

In Oracle SQL statement I need to assign variable value from Select Statement. I am doing it according to line documentation but the variable value is empty.
In SQL server the following is what I need to do.
DECLARE #variable INT;
SELECT #variable= mycolumn from myTable;
In Oracle here is the output and query that I am having problem with. I am using Toad client.
My goal is to use the variable value as part of a query.
Here is a simple example intended use.
SELECT * FROM mytable WHERE DateField >= :varCurrMoDateBeg
DECLARE
varCurrMoDateBeg DATE;
varCurrMoDateEnd DATE;
BEGIN
SELECT MONTH_BEG_DATE INTO varCurrMoDateBeg FROM
(
SELECT
CALENDAR.MONTH_BEG_DATE MONTH_BEG_DATE
FROM
CALENDAR
WHERE
CALENDAR.CAL_TYPE='M'
AND (sysdate) BETWEEN CALENDAR.MONTH_BEG_DATE AND CALENDAR.MONTH_END_DATE
) ;
--DBMS_OUTPUT.PUT_LINE(varCurrMoDateBeg);
SELECT MONTH_END_DATE INTO varCurrMoDateEnd FROM
(
SELECT
CALENDAR.MONTH_END_DATE MONTH_END_DATE
FROM
CALENDAR
WHERE
CALENDAR.CAL_TYPE='M'
AND (sysdate) BETWEEN CALENDAR.MONTH_BEG_DATE AND CALENDAR.MONTH_END_DATE
);
--DBMS_OUTPUT.PUT_LINE(varCurrMoDateEnd);
END;
SELECT :varCurrMoDateBeg, :varCurrMoDateEnd from dual;
Online sources:
SELECT INTO Statement
https://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems045.htm
plsql - Declaring a variable and setting its value from a SELECT query in Oracle - Stack Overflow
Declaring a variable and setting its value from a SELECT query in Oracle
PL/SQL SELECT INTO Statement By Practice Examples
https://www.oracletutorial.com/plsql-tutorial/plsql-select-into/
Oracle Tutorials - Assign Query Results to Variables
http://dba.fyicenter.com/faq/oracle/PL-SQL-Assign-Query-Results-to-Variables.html
Using Toad, a small example
declare
v_var date;
v_bind date :=to_date('01.01.2020','DD.MM.YYYY');
v_stm varchar2(4000);
v_counter pls_integer;
begin
select sysdate into v_var from dual ;
dbms_output.put_line(v_var);
execute immediate ' select sysdate from dual ' into v_var ;
dbms_output.put_line(v_var);
-- with bind
v_stm := ' select count(*) from dba_objects where created > :1 ' ;
execute immediate v_stm into v_counter using v_bind;
dbms_output.put_line(v_counter);
end;
/
When I ran this code
As you can see, it is a very easy piece of code that shows how to use bind variables in PL/SQL.
You could create a function for each of the dates you want to use outside of your current PL/SQL block. Here is a rough example to demonstrate how that could be made to work.
CREATE OR REPLACE FUNCTION varCurrMoDateBeg
RETURN DATE
AS
dt_Work DATE;
BEGIN
-- Replace this with your query
SELECT SYSDATE INTO dt_Work FROM dual;
RETURN dt_Work;
END varCurrMoDateBeg;
/
SELECT varCurrMoDateBeg FROM dual;

Invalid identifier error in oracle procedure for database link

I have below procedure for which i am passing db link as a parameter and create dynamic sql statement. While executing the procedure i am getting error as ORA-00904: "DB_CONNECTION_NAME": invalid identifier. I have declared the variable but still i am getting this error.
CREATE OR REPLACE PROCEDURE "EXT_SDR_RECEIVED"(in_db_link IN VARCHAR2)
AS
last_sm_id NUMBER := 0;
last_capt_date DATE;
l_sql VARCHAR2(5000);
db_connection_name VARCHAR2(100);
BEGIN
SELECT db_link INTO db_connection_name
FROM rator_monitoring_configuration.db_connection
WHERE db_link = in_db_link;
--DELETE DATA FROM TEMP_SDR_RECEIVED
DELETE FROM temp_sdr_received WHERE create_date < SYSDATE - 7;
-- first retrieve the last id (of the newest record) which has been imported at last extraction
SELECT last_task_id INTO last_sm_id
FROM capturing WHERE db_table = 'TEMP_SDR_RECEIVED';
SELECT capturing_date INTO last_capt_date
FROM capturing WHERE db_table = 'TEMP_SDR_RECEIVED';
dbms_output.PUT_LINE('DB' || db_connection_name);
-- retrieve all new records from remote SDR_O2 table and insert it into TEMP_SDR_RECEIVED where ID is greater than LAST_SM_ID
l_sql := 'INSERT INTO TEMP_SDR_RECEIVED(ID,RATING_CODE,A_NUMBER,CREATE_DATE,VOUCHER_ATTEMPT_ID,RATOR_BRAND_ID,BRAND_ID,STATUS_DESCRIPTION,ACCOUNT_PAYMENT_ID,SUBSCRIPTION_ID,DB_LINK)
SELECT SD.ID,SD.RATING_CODE,SD.A_NUMBER,to_date(substr(SD.ID, 1, 8), ''YYYYMMDD''),VA.ID,VA.BRAND_ID,BR.BRAND_ID,VA.STATUS_DESCRIPTION,VA.ACCOUNT_PAYMENT_ID,VA.SUBSCRIPTION_ID,DB_CONNECTION_NAME
FROM SDR_O2#' || db_connection_name || ' SD
JOIN VOUCHER_ATTEMPT#' || db_connection_name || ' VA
ON SD.ID = VA.SDR_ID,
RATOR_MONITORING_CONFIGURATION.BRAND BR
WHERE VA.BRAND_ID IS NOT NULL
AND BR.RATOR_BRAND_ID = VA.BRAND_ID
AND SD.RATING_CODE=''VOUCHER''
AND VA.STATUS_DESCRIPTION = ''USSD voucher''
AND SD.ID > LAST_SM_ID';
EXECUTE IMMEDIATE l_sql;
END ext_sdr_received;
You are referencing DB_CONNECTION_NAME in the select part of your dynamic query (look after VA.SUBSCRIPTION_ID). Do any of your 3 tables have that column? I suspect not.
I suspect that you wanted to select the value in the DB_CONNECTION_NAME variable instead. To do that, change that last part of the SELECT in your dynamic query like this:
'...,VA.SUBSCRIPTION_ID, ''' || DB_CONNECTION_NAME || '''
...
You may also want to look into how execute immediate supports parameter binding, so that, where possible, you can avoid having to write this ugly string concatenation code.
Also, I notice you are mixing join notations. That's asking for trouble. Stick to ANSI JOIN syntax.