Select Query in if else in Postgres Sql - sql

something like ths
if(1=1)
select * from Table_a
else
slect * from Table_b
without using functions
I am trying something like this
DO $$
DECLARE
a integer := 10;
b integer := 20;
BEGIN
IF a >b THEN
select * from online.fandi_workflow_options ;
else
select * from online.credit_workflow_options ;
END IF;
END
$$;
Can anyone help me here

select * from online.fandi_workflow_options
where a > b
union
select * from online.credit_workflow_options
where a <= b
You can usually replace a logical "if" with a "where" clause; in your case, you're selecting from two different tables, so you have to use a union. This query only works if both tables have the same columns - if not, you can select explicit column names, and add "bogus" columns to each select statement to make them identical.

Related

Check SQL SYS_REFCURSOR without changing the cursor position

I have a requirement to check if a cursor was able to get some rows from table A. If yes, then do nothing else pull rows from table B.
Currently there are two stored procedures for now.
I am trying to do this in one stored procedure.
I tried using %ROWCOUNT but it doesn't work(because it will return 0) without changing the location of the cursor.
The issue is that my output is the cursor so I don't want to make any changes to.
If I do a fetch, then it shows error also that the return type has changed.
Any idea how to do this, like even if create a copy the cursor so that the fetch and row count could be done on the copy instead of the output cursor.
Pseudo Example
create or replace PROCEDURE "proc"
(
output OUT SYS_REFCURSOR,
)
.
BEGIN
.
.
OPEN output for select * from A
END
BEGIN
//check if output was empty then
OPEN output for select * from B
.
.
END
Update:
I did as suggested
....
BEGIN
...
OPEN output for
with
A as (select ...),
,B as (select ...),
,C as (select ...),
,D as (select ...)
select * from A
union
select * from B where not exists(select null from A)
union
select * from C where not exists(select null from B)
union
select * from D where not exists(select null from C)
END;
Since I know for sure that either one these tables will have data, I also tried the below
....
BEGIN
...
OPEN output for
with
A as (select ...)
,B as (select ...)
,C as (select ...),
,D as (select ...)
select * from A
union
select * from B
union
select * from C
union
select * from D
END;
But it gives me error now that
Error(64,7): PL/SQL: ORA-01789: query block has incorrect number of result columns
The table structure foe these 4 is diff. So they might return diff columns.
Would join make sense if 3 out of 4 are empty?
It's much better to implement your requirement in the same cursor, because it will use the same point-in-time read consistency: in your approach second open opens cursor for a different time than your first cursor and really data in A and B can change already.
This approach is better:
create or replace PROCEDURE "proc"( output OUT SYS_REFCURSOR,...)
....
BEGIN
...
OPEN output for
with
A as (select ...)
,B as (select ...)
select * from A
union all
select * from B where not exists(select null from A)
END;
Another possible solution is to create pipelined table instead, like:
create or replace function ... return {collection type} PIPELINED as
...flag boolean := true;
begin
....
for i in (select * from A) loop
flag:=false;
pipe row(...)
end loop;
if flag then
for i in (select * from B) loop
flag:=false;
pipe row(...)
end loop;
end if;
end;
/
But as you can see both query are opened at different time too.

Oracle: if TABLE_A exists, return count(*), else return 0;

I want to use only one SQL statement, I have tried following one but failed:
SELECT decode(TABLE_COUNT, 0, 0, SELECT COUNT(*) FROM TABLE_A) FROM
(
SELECT COUNT(*) AS TABLE_COUNT FROM USER_TABLES WHERE TABLE_NAME = 'TABLE_A'
)
An example of the dbms_xmlgen approach that #RaymondNijland referred to in a comment:
create table table_a (id) as select level from dual connect by level <= 10;
select nvl(max(to_number(
xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml('select count(*) as c from ' || table_name))
returning content)
)), 0) as count
from user_tables
where table_name = 'TABLE_A';
COUNT
----------
10
drop table table_a purge;
select nvl(max(to_number(
xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml('select count(*) as c from ' || table_name))
returning content)
)), 0) as count
from user_tables
where table_name = 'TABLE_A';
COUNT
----------
0
You can easily extend this to query multiple tables at once, or all tables in a schema, etc., by changing the filter and adding a group-by clause.
The WITH clause may be of use in this case if the feature is available in the version of Oracle you are using. The following is what the code would look like.
NOTE: This is a SELECT statement even though it looks like PL/SQL code. The WITH clause supports the use of a PL/SQL declaration within it.
WITH
FUNCTION getCount(p_table_name IN VARCHAR2)
RETURN NUMBER IS
v_count NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM '||p_table_name INTO v_count;
RETURN mycount;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
SELECT getCount('hr.employee') FROM DUAL;
The WHEN OTHERS traps the error when the table does not exist and returns 0. If the table exists, it returns the count from the table.
Hope this works for you.

postgresql if else select query

I am trying to make a query that will compare first
first condition was to compare
the year now and
get the maximum year of view view_delinquency_allquarter
then, it will execute the first query
else second query
BEGIN
IF
select max(ctaxyear) as ctaxyear,
(select cast ( (SELECT EXTRACT(QUARTER FROM TIMESTAMP 'now()')) as int ) as yearnow) as yearnow
from view_delinquency_allquarter
where ctaxyear > year_next
THEN
select * from view_delinquency_allquarter;
ELSE
select * from view_delinquency;
END IF;
END
There are plenty of answers as well as documentation use declare var and then assignment var := (your query result)

Simplify PostgreSQL function

I have a PostgreSQL stored procedure that contains the following code:
IF something = TRUE THEN
SELECT id INTO some_id FROM some_table WHERE some conditions LIMIT 1;
RETURN QUERY SELECT * FROM some_table WHERE some conditions LIMIT 1;
ELSE
SELECT id INTO some_id FROM some_table WHERE some OTHER conditions LIMIT 1;
RETURN QUERY SELECT * FROM some_table WHERE some OTHER conditions LIMIT 1;
END IF;
DELETE FROM some_table where id = some_id;
Is there a way to simplify the above code? I guess there is nothing we can do
about the repeated code in the IF and in the ELSE, but is there a way to avoid
having 2 SELECT's every time? Is it possible to insert something in some_id while
RETURN QUERY?
If the function does only what you posted then it is not necessary:
delete from some_table
where
something and (some conditions)
or
something is not true and (some other conditions)
returning *

Same query but different tables

I'm faced with a big query that is generated in a string and executed with "OPEN pCursor FOR vQuery" and I'm trying to get the query out of the string variable and as a proper "compilable" query.
I'm having this problem where a different table is query depending on a variable
vQuery := 'SELECT ...';
IF pVar = 1 Then
vQuery := vQuery || ' FROM table1';
ELSE
vQuery := vQuery || ' FROM table2';
END IF
vQuery := vQuery || ' WHERE ...';
The two tables have pretty much the same column name. Is there a way to have this as a single query
OPEN Pcursorout FOR
SELECT ... FROM CASE WHEN pVar = 1 THEN table1 ELSE table1 END WHERE ...;
Or I'm stuck at having two queries?
IF pVar = 1 Then
OPEN Pcursorout FOR SELECT ... FROM table1 WHERE ...;
ELSE
OPEN Pcursorout FOR SELECT ... FROM table2 WHERE ...;
END IF
The select and where part are large and exactly the same for both table.
You could use a UNION and use your variable pVar to only include the results from one query in the result set.
SELECT t1.col1, t1.col2, ..., t1.col10
FROM table1 t1
WHERE pVar = 1 and ...
UNION
SELECT t2.col1, t2.col2, ..., t2.col10
FROM table1 t2
WHERE pVar <> 1 and ...
This isn't exactly what you asked about -- not being required to have duplicate lists of columns for the two select statements -- but I think it might capture your intent. It will require that the columns selected by both queries have the same datatype so there will be a (somewhat weak) constraint that the columns of both query results are the same. For example, you won't be able to add a new column to one query but not the other.
Perhaps using UNION / UNION ALL to unite both queries? The requirement for using UNION/UNION ALL is that all SELECTs being united must return columns with the same names.
So if you have
SELECT t.f1,
t.f2,
t.f3
FROM t
WHERE ...
and your other query is
SELECT q.f1,
q.f2,
q.f3
FROM q
WHERE ...
you can have both running as a single SQL statement with UNION:
SELECT t.f1,
t.f2,
t.f3
FROM t
WHERE ...
UNION
SELECT q.f1,
q.f2,
q.f3
FROM q
WHERE ...
Keep in mind that if you need to return columns that exist in one table but not in the other, you can still use UNION, just return NULL and name the column correspondingly to the column name in the table that has it.
Its a bit of a kludge and you might need to look at the performance impact, but you could use an inline view that unions the two base tables, with a flag on each part that you then compare to your variable
SELECT ...
FROM (
SELECT 1 as var, table1.*
FROM table1
UNION ALL
SELECT 2 as var, table2.*
FROM table2
) t
WHERE t.var = pVar
AND ...;
Using an inline view means you don't have to duplicate the main select-list or the where clause etc. If the tables have different columns then you can (and maybe should anyway) only select the columns in the inner queries that will be referenced in the outer select-list.