Select data depend with IF ELSE condition - oracle

I have a query as below :
SELECT R.*
FROM
(
WITH TABLE_X AS
(
SELECT A,B,C FROM Y
)
--PSEUDO CODE
IF (COUNT(TABLE_X.*) > 0)
THEN SELECT CONCAT(A ,B, C) FROM TABLE_X
ELSE 'No Data'
END
) R
In this case, If TABLE_X have data, the selection will return A,B,C. In others way, this will return something else like 'No data'.
Please help me clarify and suggest some soluiton on it.
Thank you for your attention.

If there is at most one row in TABLE_X, then you can use aggregation:
WITH TABLE_X AS (
SELECT A, B, C FROM Y
)
SELECT (CASE WHEN COUNT(*) = 0 THEN 'No Data'
ELSE MAX(A || B || C)
END) as col
FROM TABLE_X;
Alternatively, use UNION ALL:
WITH TABLE_X AS (
SELECT A, B, C FROM Y
)
SELECT A || B || C as col
FROM TABLE_X
UNION ALL
SELECT 'No Data'
FROM Dual
WHERE NOT EXISTS (SELECT 1 FROM TABLE_X);

Looking too you query i think you simply need
select nvl( A||B,||C , 'No data')
from y

Related

Unpivot Multiple columns in Oracle is not working

I have a table like below
Process_1
Tab1_Count
Tab1_Process_Count
Tab1_Status
Process_2
Tab2_Count
Tab2_Process_Count
Tab2_Status
Tab1_Process
123
123
Equal
Tab2_Process
123
126
Not Equal
I am trying to Unpivot the above like the below
TABLEPROCESS
Tab_Count
Process_Count
Status
Tab1_Process
123
123
Equal
Tab2_Process
123
123
Not Equal
With the below query
SELECT *
FROM
(
SELECT 'Tab1' AS tab1_Process,
count(tb1.ID) AS tab1_count,
count(tbp1.ID) AS tab1_Process_count,
CASE WHEN count(tb1.ID)=count(tbp1.ID) THEN 'Equal' ELSE 'Not Equal' END AS Tab1_Status,
'Tab2' AS tab2_Process,
count(tb2.ID) AS tab2_count,
count(tbp2.ID) AS tab2_Process_count,
CASE WHEN count(tb2.ID)=count(tbp2.ID) THEN 'Equal' ELSE 'Not Equal' END AS Tab2_Status
FROM table1 tb1
LEFT JOIN table1_process tbp1 ON tbp1.ID = tb1.ID
LEFT JOIN table2 tb2 ON tb2.ID = tb1.ID
LEFT JOIN table1_process tbp2 ON tbp2.ID = tb2.ID
)
UNPIVOT
(
(TABLEPROCESS,STATUS)
FOR COUNT IN
(
(Tab1_Count,Tab2_Count) AS 'Tab_Count',
(Tab1_Process_Count,Tab2_Process_Count) AS 'Process_Count',
(Tab1_Status,Tab2_Status) AS 'STATUS'
)
)
but it is giving me error -- ORA-00907: missing right parenthesis
As per comment by Alex Poole tried CROSS APPLY method
SELECT *
FROM
(
SELECT 'Tab1' AS tab1_Process,
count(tb1.ID) AS tab1_count,
count(tbp1.ID) AS tab1_Process_count,
CASE WHEN count(tb1.ID)=count(tbp1.ID) THEN 'Equal' ELSE 'Not Equal' END AS Tab1_Status,
'Tab2' AS tab2_Process,
count(tb2.ID) AS tab2_count,
count(tbp2.ID) AS tab2_Process_count,
CASE WHEN count(tb2.ID)=count(tbp2.ID) THEN 'Equal' ELSE 'Not Equal' END AS Tab2_Status
FROM table1 tb1
LEFT JOIN table1_process tbp1 ON tbp1.ID = tb1.ID
LEFT JOIN table2 tb2 ON tb2.ID = tb1.ID
LEFT JOIN table1_process tbp2 ON tbp2.ID = tb2.ID
)
CROSS APPLY
VALUES (
(tab1_Process,Tab1_Count,Tab1_Process_Count,Tab1_Status),
(tab2_Process,Tab2_Count,Tab2_Process_Count,Tab2_Status),
) (Process,Tab_Count,Process_Count,Status);
It is working in SQL Server but it is giving ORA-00903: invalid table name in oracle
I am new to oracle, Please help
Achieved the expected result using the below UNPIVOT Query
SELECT TABLEPROCESS,TAB_COUNT,PROCESS_COUNT,STATUS
FROM
(
SELECT 'Tab1' AS tab1_Process,
count(tb1.ID) AS tab1_count,
count(tbp1.ID) AS tab1_Process_count,
CASE WHEN count(tb1.ID)=count(tbp1.ID) THEN 'Equal' ELSE 'Not Equal' END AS Tab1_Status,
'Tab2' AS tab2_Process,
count(tb2.ID) AS tab2_count,
count(tbp2.ID) AS tab2_Process_count,
CASE WHEN count(tb2.ID)=count(tbp2.ID) THEN 'Equal' ELSE 'Not Equal' END AS Tab2_Status
FROM table1 tb1
LEFT JOIN table1_process tbp1 ON tbp1.ID = tb1.ID
LEFT JOIN table2 tb2 ON tb2.ID = tb1.ID
LEFT JOIN table1_process tbp2 ON tbp2.ID = tb2.ID
)
UNPIVOT
(
(TABLEPROCESS,TAB_COUNT,PROCESS_COUNT,STATUS)
FOR (t,c,p,s)
IN
(
(tab1_Process,Tab1_Count,Tab1_Process_Count,Tab1_Status),
(tab2_Process,Tab2_Count,Tab2_Process_Count,Tab2_Status)
)
);

How can i make dynamic pl/sql?

I would like to make dynamic pl/sql using type variables in parameter values.
parameter value
>
type = {'name + place', 'resno', 'hpno', 'telno'};
for example
if i got parameter values('resno', 'hpno')
Two combine queries're required(2 union all)
so, it means that The number of queries depends on the parameter value.
select * from (
--repeatation
select * from
(select a.custnm
, 'name + place' as vtype
, a.custnm || '-' || c.pjtcd || '-' || c.dong || '-' || c.ho as con
, count(a.custid) as nodup
from custtable a
, thng c
where a.custid = c.custid(+)
group by a.custnm, c.pjtcd, c.dong, c.ho
having count(a.custid) > 1) x
--/repeatation
union all
--repeatation
select * from
(select a.custnm
, 'resno' as vtype
, a.resno as condup
, count(a.custid) as nodup
from custtable a
group by a.custnm, a.resno
having count(a.custid) > 1) x2
--repeatation
union all
--repeatation
select * from
(select a.custnm
, 'hpno' as vtype
, a.hpno as condup
, count(a.custid) as nodup
from custtable a
group by a.custnm, a.hpno
having count(a.custid) > 1) x3
--repeatation
union all
--repeatation
select * from
(select a.custnm
, 'telno' as vtype
, a.telno as condup
, count(a.custid) as nodup
from custtable a
group by a.custnm, a.telno
having count(a.custid) > 1) x4
--repeatation
)
order by decode(vtype, 'name +`enter code here` place', 1 ,'resno', 2 ,'hpno', 3, 'telno', 4), nodup desc
plz let me know how to make plsql with parameter value
This is a SELECT statement. The way it is written now, it is SQL, not PL/SQL, and my suggestion is to leave it that way. Instead of writing a horrible PL/SQL (dynamic SQL usually isn't nice), why wouldn't you create a view, based on that statement?
create or replace view v_my_view as
select * from (
--repeatation
select * from
(select a.custnm
, 'name + place' as vtype
<snip>
Once you do that, use it anywhere you want (PL/SQL included).

How can I join these two select queries into one query?

this is my first time posting, so I am sure I will get a number of things wrong. Do not hesitate to correct me and I will do everything I can to clarify.
In Oracle SQL Developer, I am trying to take two separate SELECT statements and combine them to get one row of results. Unfortunately, because this is sensitive data, I am unable to give any results from the statements individually, but instead, just the SQL statements themselves. I suspect I should be able to join these two on the field "emplid" but just cannot get there. Any help is greatly appreciated! Here is the code below, please mind the syntax :)
1st Select statement is giving me a list of people that were paid in 2017:
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
And 2nd Select statement would be a list of the deductions taken for the employees that were identified in the first statement:
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
Ideally, what I'd like to do is put in a value in place of 'XXXXXX' and get one row of data with the two combined statements.
Thanks everyone!
To do this, we stick each SELECT statement into a subquery and give that subquery an alias to refer to in the main queries select statement:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
) t1
INNER JOIN
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
) t2 ON
t1.empid = t2.empid
We just treat each derived table/subquery as it's own table and join them on empid. You can tweak the SELECT statement at the top as needed.
This is similar to creating a view for both sql statements and then referencing the views in a third sql statement.
An alternative way of doing this is to use CTE (Common Table Expressions) to house the separate sql. There's no performance advantage here, but you might find it easier to read.
WITH t1 as
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
),
t2 AS
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
)
SELECT t1.*, t2.*
FROM t1 INNER JOIN t2 ON
t1.empid = t2.empid
Basically you do something like
select blah, blah.. (your second query )
AND G.EMPLID IN ( SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
)
So basically I have used your first query in you second query. I removed the DISTINCT, as its not needed.
I hope that makes sense.

Error in my Subquery Factoring (WITH) Clause

I have an error when I run this script :
WITH q AS (
SELECT COUNT(id)
FROM test
)
SELECT 1,
CASE
WHEN q=0 then 'toto'
ELSE 'titi'
END
FROM dual;
I must to use a Subquery Factoring (WITH) clause.
The idea is to display 'toto' when the count equal 0 else I must display 'titi'.
Use an alias for the result, and FROM q
WITH q AS (
SELECT COUNT(id) as total
FROM test
)
SELECT 1,
CASE
WHEN q.total = 0 THEN 'toto'
ELSE 'titi'
END
FROM q;
You can simplify it to:
SELECT 1,
CASE COUNT(*) WHEN 0 then 'toto' ELSE 'titi' END
FROM test;
The error in your query is that you have created a named subquery q but then you are selecting the column q from the DUAL table (which does not have a column q).
You can fix your query like this:
WITH q AS (
SELECT COUNT(id) AS cnt -- name this column
FROM test
)
SELECT 1,
CASE WHEN cnt = 0 -- use the column you named previously
THEN 'toto'
ELSE 'titi'
END
FROM q; -- use the named subquery q not the dual table

Select statement inside NVL

I'm trying to run the following query:
select a.*,
case when NVL (SELECT max(b.field1)
FROM b
where b.field2 = a.tbl_a_PK , 'TRUE') = 'TRUE'
then 'has no data in b'
else 'has data in b' end as b_status
from a
I checked and the select inside the nvl returns only 1 value (so there shouldn't be a problem there).
However I'm getting 'ORA-00936: missing expression'
NVL() requires 2 parameters: expression to test and default value e.g. nvl(some_field, 111). You just need to isolate query parameter by braces and provide second parameter like in this statement:
select nvl( (select 1 from dual), 34) from dual
In your variant parser expects comma after SELECT keyword and can't parse remaining string.
Exactly your statement must look like this:
select
a.*,
case when NVL(
( SELECT max(b.field1)
FROM b
where b.field2 = a.tbl_a_PK
),
'TRUE'
) = 'TRUE'
then 'has no data in b'
else 'has data in b' end as b_status
from a
Hope this helps ...
Update
In terms of performance is better to use exists rather then max :
select
a.*,
case when exists
( SELECT null
FROM b
where b.field2 = a.tbl_a_PK
and
b.field2 is not null
and
rownum = 1
),
then 'has data in b'
else 'has no data in b' end as b_status
from a
If you're searching for records in a which have/don't have associated records in b
select a.*,
case when b.field2 is null then 'has no data in b'
else 'has data in b'
as b_status
from a left outer join b
on a.tbl_a_PK = b.field2;
Should do it
the NVL(string1, replace_with) function requires 2 parameters, see docs here:
http://www.techonthenet.com/oracle/functions/nvl.php
Ora 10g docs: http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions105.htm
Since you know the problem, this query can fix it:
select a.*,
case
when (SELECT NVL(b.field2, 0) FROM b where b.field2 = a.tbl_a_PK and rownum = 1) > 0 then
'has data in b'
else
'has no data in b'
end b_status
from a
and runs faster.
You don't need max() to check if the value exists in another table, simply check if the primary key is not null.

Resources