How to use the result of SQL aggregate in IF statement - sap

I am trying to script a procedure in HANA, and I have a requirement to compare the Week ID's of 2 tables. If the Week ID1 > Week ID2, I have to insert the new records to table which has ID2. I tried the below logic, but that did not work.
Here, the logic inside the IF is not executing, though the
VAR1 VARCHAR(2);
VAR2 VARCHAR(2);
BEGIN
SELECT MAX(FISCAL_WK) AS VAR1 FROM "XXX"."OUTLOOK_FACTS";
SELECT MAX(FISCAL_WK) AS VAR2 FROM "XXX"."OUTLOOK";
IF :VAR2 > :VAR1 THEN
SELECT MAX(OUTLOOKID) AS TEST FROM "XXX"."OUTLOOK_FACTS";
END IF;
END;
I am pretty new to this, so please help.

In your code example you don't actually assign values to :VAR1 or :VAR2, so both variables stay empty.
Try with
SELECT MAX(FISCAL_WK) AS VAR1 into :VAR1 FROM "XXX"."OUTLOOK_FACTS";
SELECT MAX(FISCAL_WK) AS VAR2 into :VAR2 FROM "XXX"."OUTLOOK";
IF :VAR2 > :VAR1 THEN
SELECT MAX(OUTLOOKID) AS TEST FROM "XXX"."OUTLOOK_FACTS";
END IF;
You could, however also just pack everything in a single SQL statement. But that's for you do choose :)

For that insert you don't need any procedural code.
You could do it in straight SQL:
select case
when max_fisc > max_fisc_fact then
max_id_fact
else
-1
end as VALUE_TO_BE_INSERTED
from (
select max(o.fiscal_wk) as max_fisc, max(o.outlookid) as max_id
, max(f.fiscal_wk) as max_fisc_fact, max(f.outlookid) as max_id_fact
from outlook o
cross join outlook_facts f);
Just pack this SQL into your INSERT statement and you're done.
- Lars

Related

PLSQL Selecting from table using an array into a variable

I am trying to select some records from a table using an array into the variable init_av_days but its not working out. init_av_days is to be committed to another table after this select query. How best do you suggest i do this?
declare
myarray APEX_APPLICATION_GLOBAL.VC_ARR2;
init_av_days varchar2(10);
begin
myarray := APEX_UTIL.STRING_TO_TABLE(:P592_AVAILABILITY_DAYS);
For i in 1.. myarray.count loop
select availability_days
into init_av_days
from sl_available_days
where location_code = :P592_LOCATION_CODE
and availability_days = myarray(i);
end loop;
end;
init_av_days is to be committed to another table after this select query
Best? Skip PL/SQL entirely, I'd say. Something like this:
insert into another_table (some_column)
select availability_days
from sl_available_days
where location_code in = (select regexp_substr(:P592_LOCATION_CODE, '[^:]+', 1, level)
from dual
connect by level <= regexp_count(:P592_LOCATION_CODE, ':') + 1
)
and availability_days = <I don't know what APEX_APPLICATION_GLOBAL.VC_ARR2 contains>
This code should be fixed because I don't know the last condition; if you know how, do it. If not, explain what's in vcc_arr2, maybe we can assist.

looping and executing dynamic query in Oracle

I'm having some trouble truncating some tables that get generated in my base.
The table names get saved and I can do it manually, but I wanted to see if it could be automated until its fixed.
What I've done so far is get all the table names and a id/number into my own help table. My errors begin around the loop/Execute immediate where im not sure how to use the data I've gotten in the syntax and i cant find any similar examples.
create table HlpTruncTable as SELECT SUBSTR(argument, 3) as tblName, rownum as Nr
FROM tblLogHlp
WHERE status = 'E' and argument like '0,awfh%' and LAST_UPDATE <= ADD_MONTHS(sysdate,-1);
for i in 1..(select max(nr) from HlpTruncTable) LOOP
execute immediate TRUNCATE TABLE (select tblName from HlpTruncTable where nr = (i));
END LOOP;
drop table hlpTruncTable;
I would do it like this:
declare
cursor HlpTruncTable is
SELECT SUBSTR(argument, 3) as tblName
FROM tblLogHlp
WHERE status = 'E' and argument like '0,awfh%' and LAST_UPDATE <= ADD_MONTHS(sysdate,-1);
BEGIN
FOR aTable IN HlpTruncTable LOOP
execute immediate 'TRUNCATE TABLE '||aTable.tblName;
END LOOP;
END;

Oracle SQL - Check duplicates in whole table

I have a table with columns
BIN_1_1
BIN_1_2
BIN_1_3
all the way to BIN_10_10
The user enter a value, and the value needs to be checked in all the columns starting from BIN_1_1 to BIN_10_10.
If there is a duplicate value, it prints a msg and gets out of the procedure / function.
How do I go about this?
Do you mean something like this?
create or replace
procedure check_duplicate( p_val yourtable.bin_1_1%type) is
v_dupl number;
begin
begin
select 1 into v_dupl from yourtable
where p_val in (bin_1_1, bin_1_2, ... bin_10_10) and rownum <=1;
exception
when no_data_found
then v_dupl := 0;
end;
if v_dupl = 1
then
dbms_output.put_line('your message about duplication');
return;
else
dbms_output.put_line('here you can do anything');
end if;
end;
Try this query,
INSERT INTO yourTable values ('your values') where
WHERE BIN_1_1 NOT IN (
SELECT bins FROM (
SELECT BIN_1_1 FROM yourTable
UNION
SELECT BIN_1_2 FROM yourTable
UNION
SELECT BIN_1_3 FROM yourTable
) AS bins
)
P.S. I din't run this query.
Unpivot your table, then it's easy. You may want to write a query that will write the query below for you. ("Dynamic" SQL just to save yourself some work.)
select case when count(*) > 1 then 'Duplicate Found' end as result
from ( select *
from your_table
unpivot (val for col in (BIN_1_1, BIN_1_2, ........, BIN_10_10))
)
where val = :user_input;
Here :user_input is a bind variable - use whatever mechanism works for you (end-user interface, SQL Developer, whatever).
You need to decide what outcome you want when the value is not duplicated in the table - you didn't mention anything about that.

Run an SQL script only if a selection over a table before it gives a result. If it doesn't give a result the SQL script should not run

I would like an SQL script to run only if a SQL command selection over a table give a result.
If it doesn't give a result the SQL script should not run.
Will this be possible to do?
I might help:
IF ( select count(1) from ( _your selection_ ) a ) > 0 THEN
_RUN your script_;
END IF
this is one way:
DECLARE
type t1
IS
TABLE OF hr.employees.first_name%type;
t11 t1;
BEGIN
SELECT e.first_name bulk collect
INTO t11
FROM hr.employees e
WHERE E.EMPLOYEE_ID=999;
IF(t11.count! =0) THEN
FOR i IN 1..t11.count/*here you can write your own query */
LOOP
dbms_output.put_line(t11(i));
END LOOP;
ELSE
dbms_output.put_line('oh..ho..no rows selected' );
END IF;
END;
/
any clarification plz let me know..

Using variables in Oracle script

There is a complex query which generates a report. The query has several sub queries that generate 3-columns table for different products. Each sub query returns one row. All returned rows then need to be united.
But there is one requirement. If there are no result rows for a sub query we need to include the corresponding product to the final report anyway, but specify that Trades_Count is equal to zero.
I can achieve this using set of variables. The following code will work perfectly in MS SQL Server:
DECLARE #PRODUCT_NAME_1 nvarchar(100);
DECLARE #OFFER_VALID_DATE_1 datetime;
DECLARE #TRADES_COUNT_1 int;
DECLARE #PRODUCT_NAME_2 nvarchar(100);
DECLARE #OFFER_VALID_DATE_2 datetime;
DECLARE #TRADES_COUNT_2 int;
--Product 1
select #PRODUCT_NAME_1 = PRODUCT_NAME, #OFFER_VALID_DATE_1 = MAX(EXPIRY_DATE), #TRADES_COUNT_1 = COUNT(DEAL_NUMBER)
from (
--Data extractions with several joins goes here....
) as TempTable1
GROUP BY PRODUCT_NAME
--Product 2
select #PRODUCT_NAME_2 = PRODUCT_NAME, #OFFER_VALID_DATE_2 = MAX(EXPIRY_DATE), #TRADES_COUNT_2 = COUNT(DEAL_NUMBER)
from (
--Data extractions with several joins goes here....
) as TempTable2
GROUP BY PRODUCT_NAME
SELECT ISNULL(#PRODUCT_NAME_1,'Product 1') AS PRODUCT_NAME, #OFFER_VALID_DATE_1 AS MAX_MATURITY, ISNULL(#TRADES_COUNT_1,0)
UNION
(
SELECT ISNULL(#PRODUCT_NAME_2,'Product 2') AS PRODUCT_NAME, #OFFER_VALID_DATE_2 AS MAX_MATURITY, ISNULL(#TRADES_COUNT_2,0)
)
I think that I haven’t used anything T-SQL specific, but pure ANSI-SQL (I’m not 100% sure though).
So this is not working in Oracle.
First of all it requires having only one DECLARE keyword. Then it forces me using Begin … End execution scope. Then it doesn’t allow me to assign variables like I do (see example above) – I need to use “Select INTO” statement instead. After all calculations are done it doesn’t allow me selecting values from local variables. Heck.
Does anyone know how to make it work in Oracle?
Thanks!
PL/SQL is different than t-sql, I did a change with some comments for you, but definitely look at the links from Andy. This was ran in oracle's free SQL Developer (which also has a "Translation Scratch Handler (tools>Migration>Translation Scratch Handler) that may be of use.
--this creates a refcursor to allow us to simply print the results
var refc refcursor
/
declare --here we declare our variables
product_name_1 varchar2(15) ;
offer_valid_date_1 date ;
trade_count_1 number ;
product_name_2 varchar2(15) ;
offer_valid_date_2 date ;
trade_count_2 number ;
begin
begin --this creates a block so we may handle any exceptions just to this
select PRODUCT_NAME, MAX(EXPIRY_DATE), COUNT(DEAL_NUMBER)
into product_name_1 , offer_valid_date_1 , trade_count_1
--in oracle you select INTO, not var=COL
from (
--Data extractions with several joins goes here....
select
123 PRODUCT_NAME,
sysdate EXPIRY_DATE,
5 DEAL_NUMBER
from dual --this is a 'fake' table to generate some data for testing
) TempTable1 --drop the "as"
GROUP BY PRODUCT_NAME ;
exception --if not data is found, then this error is thrown
--if multiple values are thrown an error will also be thrown (not caught here)
when no_data_found then
product_name_1 := null ; --note, to do a var = , we use "var := value;"
offer_valid_date_1 := null;
trade_count_1 := null;
end ;
begin
select PRODUCT_NAME, MAX(EXPIRY_DATE), COUNT(DEAL_NUMBER)
into product_name_2 , offer_valid_date_2 , trade_count_2
--in oracle you select INTO, not var=COL
from (
--Data extractions with several joins goes here....
select 555 PRODUCT_NAME, sysdate EXPIRY_DATE, 6 DEAL_NUMBER
from dual
) TempTable2 -- drop the "as"
GROUP BY PRODUCT_NAME ;
exception --if not data is found, then this error is thrown
--if multiple values are thrown an error will also be thrown (not caught here)
when no_data_found then
product_name_2 := null ;
offer_valid_date_2 := null;
trade_count_2 := null;
end ;
open :refc for --you cannot just have a select statement, you must "open" a cursor for it
--oracle IsNull is NVL (or NVL2 or you can do a case or decode...)
SELECT nvl(PRODUCT_NAME_1,'Product 1') AS PRODUCT_NAME
, OFFER_VALID_DATE_1 AS MAX_MATURITY
, nvl(TRADE_COUNT_1,0)
FROM DUAL --you also must have a table, DUAL is an oracle table for this tasks
UNION
SELECT nvl(PRODUCT_NAME_2,'Product 2') AS PRODUCT_NAME
, OFFER_VALID_DATE_2 AS MAX_MATURITY
, nvl(TRADE_COUNT_2,0)
FROM DUAL;
end ;
/
--now print the results, if you did this in a proc you would simple have this as an output
print refc;
-------------
PRODUCT_NAME MAX_MATURITY NVL(:B1,0)
-------------------------------------- ----------------------
123 18.FEB.2011 08:43 1
555 18.FEB.2011 08:43 1
Oracle concepts used here:
Dual Table , NVL, Variables, pl/sql Exception
and look at this http://www.dba-oracle.com/t_convent_sql_server_tsql_oracle_plsql.htm
PL/SQL formats procedural blocks differently than T-SQL.
You'll want to use the following structure:
DECLARE
astring varchar2(1000);
anumber number;
BEGIN
my SQL code here...
END;
You don't use the # either in PL/SQL. Just use variables names directly.