Issue With GROUP BY In Query - oracle

First of all, thanks in advance for any help anyone can offer!
I'm fairly new to Oracle, so I apologize if this question is stupid...
I'm having an issue getting a query to run properly, and the issue is with the GROUP BY clause in the query.
When running the query, I get the error stating that it's not a GROUP BY statement?? Not really sure what that means.
Here is the query:
with SUB_GRP_LVL_1 as
(
select sg.HCC_ID,sge.SUB_GROUP_NAME
from XXXX_ODS.GROUP_T g
Join XXXX_ODS.SUB_GROUP sg
on g.GROUP_KEY=sg.GROUP_KEY
and g.HCC_ID NOT IN('A0002','A0003','A0004','A0005','A0021','A0022','A0041','A0042','A0081','A0121','A0061')
and sg.REC_SRC_CD='HS1'
and sg.LEVEL_NBR=1
join XXXX_ODS.SUB_GROUP_EFF sge
on sge.SUB_GROUP_KEY=sg.SUB_GROUP_KEY
---and sge.CURRENT_INDC=1
and sge.ACTIVE_INDC=1
)
,
SUB_GRP_LVL_2 as
(
select sg.HCC_ID,sge.SUB_GROUP_NAME
from XXXX_ODS.GROUP_T g
Join XXXX_ODS.SUB_GROUP sg
on g.GROUP_KEY=sg.GROUP_KEY
and g.HCC_ID NOT IN('A0002','A0003','A0004','A0005','A0021','A0022','A0041','A0042','A0081','A0121','A0061')
and sg.REC_SRC_CD='HS1'
and sg.LEVEL_NBR=2
join XXXX_ODS.SUB_GROUP_EFF sge
on sge.SUB_GROUP_KEY=sg.SUB_GROUP_KEY
and sge.ACTIVE_INDC=1
)
,
GRP_BEN_PL_ID as
(
select sg.SUB_GROUP_KEY,bpe.HCC_BENEFIT_PLAN_ID , sgbp.EFFECTIVE_DT, sgbp.EXPIRATION_DT, pe.FUNDING_TYPE, pe.HCC_PROD_ID, pe.STATE_CD, pe.SUB_COMPANY
from XXXX_ODS.GROUP_T g
Join XXXX_ODS.SUB_GROUP sg
on g.GROUP_KEY=sg.GROUP_KEY
and g.HCC_ID NOT IN('A0002','A0003','A0004','A0005','A0021','A0022','A0041','A0042','A0081','A0121','A0061')
and g.REC_SRC_CD='HS1'
JOIN XXXX_ODS.SUB_GROUP_BENEFIT_PLAN sgbp
on sg.SUB_GROUP_KEY=sgbp.SUB_GROUP_KEY
---and sgbp.CURRENT_INDC=1
and sgbp.ACTIVE_INDC=1
join XXXX_ODS.BENEFIT_PLAN_EFF bpe
on sgbp.BENEFIT_PLAN_KEY = bpe.BENEFIT_PLAN_KEY
and bpe.ACTIVE_INDC=1
join XXXX_ods.product_eff pe
on bpe.PRODUCT_KEY=pe.product_key
and pe.ACTIVE_INDC=1
)
select
BLK_1.SUB_GROUP_KEY,ACCT_NBR AS GROUPID,
SUB_GRP_ID,
DIVISION_ID
,GRP_BEN_PL_ID.HCC_BENEFIT_PLAN_ID
,INVOICE_NBR
,'CMD' BUSTYPE,
GRP_BEN_PL_ID.FUNDING_TYPE AS BUSSUBTYPE,
GRP_BEN_PL_ID.HCC_PROD_ID AS PROCODE,
'' AS PREMIUMTYPE,
INV.CURRENT_INVOICED_AMT AS PREMIUMBILLED,
INV.CURRENT_INVOICED_AMT AS PREMIUMDUEDATE,
'' AS PREMIUMPAID,
'' AS PREMIUMAPPLYDATE,
COUNT(invl.INVOICE_LINE_KEY) AS CONTRACTSXXXXL,
'' AS MEMBERSXXXXL
--ACCOUNT_TYPE
,DECODE (UPPER(GRP_BEN_PL_ID.STATE_CD),'NEBRASKA','NE','IOWA','IA') STATE,
GRP_BEN_PL_ID.SUB_COMPANY LGL_ENTITY,
LEVEL_NBR
from
(
select
g.GROUP_KEY, sg.SUB_GROUP_KEY, g.HCC_ID ACCT_NBR,ge.GROUP_NAME ACCT_NAME,substr(sg.HCC_ID, 1,instr(sg.hcc_id,'-',1,2)-1) SUB_GRP_ID,sg.HCC_ID DIVISION_ID,ce.FIRST_EFFECTIVE_DT,
add_months(
decode(ce.EFFECTIVE_DT,TO_DATE('01/01/1800','MM/DD/YYYY'),ce.FIRST_EFFECTIVE_DT,ce.EFFECTIVE_DT),ce.RENEWAL_INTERVAL) RENVL_DT, ce.ACCOUNT_TYPE
, sg.LEVEL_NBR
from
XXXX_ODS.CUSTOMER_EFF ce
join XXXX_ODS.GROUP_T g
on g.CUSTOMER_KEY=ce.CUSTOMER_KEY
Join XXXX_ODS.SUB_GROUP sg
on g.GROUP_KEY=sg.GROUP_KEY
and g.HCC_ID NOT IN('A0002','A0003','A0004','A0005','A0021','A0022','A0041','A0042','A0081','A0121','A0061')
and g.REC_SRC_CD='HS1'
and sg.LEVEL_NBR=2
and g.HCC_ID not like 'TEST%'
join XXXX_ODS.GROUP_EFF ge
on ge.GROUP_KEY = g.GROUP_KEY
and ge.CURRENT_INDC=1
union
select
gp.GROUP_KEY,
sgp.SUB_GROUP_KEY, gp.HCC_ID ACCT,gep.GROUP_NAME, sgp.HCC_ID SUB_GRP, NULL DIVISION,cep.FIRST_EFFECTIVE_DT,
add_months(decode(cep.EFFECTIVE_DT,TO_DATE('01/01/1800','MM/DD/YYYY'),cep.FIRST_EFFECTIVE_DT,cep.EFFECTIVE_DT),cep.RENEWAL_INTERVAL) RENVL_DT,
cep.ACCOUNT_TYPE, sgp.LEVEL_NBR
from
XXXX_ODS.CUSTOMER_EFF cep
join XXXX_ODS.GROUP_T gp
on gp.CUSTOMER_KEY=cep.CUSTOMER_KEY
Join XXXX_ODS.SUB_GROUP sgp
on gp.GROUP_KEY=sgp.GROUP_KEY
and gp.HCC_ID NOT IN('A0002','A0003','A0004','A0005','A0021','A0022','A0041','A0042','A0081','A0121','A0061')
and gp.REC_SRC_CD='HS1'
and sgp.LEVEL_NBR=1
and gp.HCC_ID not like 'TEST%'
join XXXX_ODS.GROUP_EFF gep
on gep.GROUP_KEY = gp.GROUP_KEY
and gep.CURRENT_INDC=1
and not exists
(
select 'X'
from
XXXX_ODS.GROUP_T gi
Join XXXX_ODS.SUB_GROUP sgi
on gi.GROUP_KEY=sgi.GROUP_KEY
and gi.HCC_ID NOT IN('A0002','A0003','A0004','A0005','A0021','A0022','A0041','A0042','A0081','A0121','A0061')
and gi.REC_SRC_CD='HS1'
and sgi.LEVEL_NBR=2
and gi.HCC_ID not like 'TEST%'
where
gp.HCC_ID=gi.HCC_ID
and sgp.HCC_ID=substr(sgi.HCC_ID, 1,instr(sgi.hcc_id,'-',1,2)-1)
)
) BLK_1
join SUB_GRP_LVL_1
on SUB_GRP_LVL_1.HCC_ID=BLK_1.SUB_GRP_ID
left join SUB_GRP_LVL_2
on SUB_GRP_LVL_2.HCC_ID=BLK_1.DIVISION_ID
left join GRP_BEN_PL_ID
on GRP_BEN_PL_ID.SUB_GROUP_KEY=BLK_1.SUB_GROUP_KEY
LEFT Join XXXX_ODS.INVOICE inv
on inv.BILL_TO_GROUP_KEY = BLK_1.GROUP_KEY
LEFT JOIN XXXX_ODS.INVOICE_BILLING_CATEGORY invbc
on invbc.INVOICE_KEY = inv.INVOICE_KEY
LEFT JOIN XXXX_ODS.INVOICE_LINE invl
on invl.INVOICE_BILLING_CATEGORY_KEY = invbc.INVOICE_BILLING_CATEGORY_KEY
GROUP BY
GRP_BEN_PL_ID.SUB_GROUP_KEY,
ACCT_NBR, --AS GROUPID,
SUB_GRP_ID,
DIVISION_ID
,GRP_BEN_PL_ID.HCC_BENEFIT_PLAN_ID
,INVOICE_NBR
,BUSTYPE
,GRP_BEN_PL_ID.FUNDING_TYPE,
,GRP_BEN_PL_ID.HCC_PROD_ID --AS PROCODE,
,PREMIUMTYPE
,INV.CURRENT_INVOICED_AMT
PREMIUMBILLED,
INV.CURRENT_INVOICED_AMT --AS PREMIUMDUEDATE,
,PREMIUMPAID
,PREMIUMAPPLYDATE
,MEMBERSXXXXL
ACCOUNT_TYPE
,STATE_CD,
GRP_BEN_PL_ID.SUB_COMPANY,
,LEVEL_NBR
order by ACCT_NBR,SUB_GRP_ID,LEVEL_NBR,DIVISION_ID
;
Thanks!

NEW ANSWER BASED ON COMMENT
Sorry I should have looked a bit closer I read the statement 'I get the error stating that it's not a GROUP BY statement' saw the count and made an assumption with my original answer.
With the further information provided in the comments I think the issue is actually that you are using the column alias in the group by.
When grouping you actually have to use the field names not the alias, if you have a static value (in this case '' AS MEMBERSXXXXL) you do not need to group by it SO
incorrect select using alias in the group by
select column1, column2 || column 3 as test2, '' as test, count(1) as cnt
from table
group by column1, test2, test
correct select omitting static value and putting full field in the group by
select column1, column2 || column 3 as test2, '' as test, count(1) as cnt
from table
group by column1, column2 || column 3
ORIGINAL ANSWER BELOW
where you have a count, min, max, sum ect within your select statement you need to tell it how to group the other columns....
you have
COUNT(invl.INVOICE_LINE_KEY) AS CONTRACTSXXXXL,
This means you will need a group by clause on your select.
Good resource for basics of this is
https://www.oracletutorial.com/oracle-basics/oracle-group-by/

Related

Error when running a sub query in Oracle SQL

I am trying to join three tables using a sub query.
The result of the first left outer join is to be used with another table to get a composite view with all attributes.
I am getting an error where the compile says, Unknown Command for the table in the second join clause.
When I create two independent views and then join then it works fine.
(select
l.ENROLLED_CONTENT,
l.LEARNING_ENROLLMENT_LEARNER,
l.EMPLOYEE_ID,
l.JOB_FAMILY_GROUP,
l.EMPLOYEE_TYPE,
l.JOB_FAMILY,
l.LEARNING_ENROLLMENT,
l.COMPLETION_STATUS,
l.COMPLETION_DATE,
l.EXPIRATION_DATE,
l.CF_LRV_LEARNING_CONTENT_NUMBER,
l.LEARNING_CONTENT_DETAIL,
l.LEARNING_CONTENT_TYPE,
l.LESSON_TYPE,
e.id# "WK_WORKER_ID"
from tgt_workday.learning l
left outer join ods_hrmaster.employee e
on l.EMPLOYEE_ID = e.employee#) t1
left outer join ( select
per_ids_id,
per_id,
id_pureid from
ods_pure.person_ids
) t2 on t1.wk_worker_id = t2.value where t2.type = 'Employee ID';
You can write it in a simple way. There is no need to make sub-queries as:
SELECT L.ENROLLED_CONTENT,
L.LEARNING_ENROLLMENT_LEARNER,
L.EMPLOYEE_ID,
L.JOB_FAMILY_GROUP,
L.EMPLOYEE_TYPE,
L.JOB_FAMILY,
L.LEARNING_ENROLLMENT,
L.COMPLETION_STATUS,
L.COMPLETION_DATE,
L.EXPIRATION_DATE,
L.CF_LRV_LEARNING_CONTENT_NUMBER,
L.LEARNING_CONTENT_DETAIL,
L.LEARNING_CONTENT_TYPE,
L.LESSON_TYPE,
E.ID# "WK_WORKER_ID"
FROM TGT_WORKDAY.LEARNING L
LEFT OUTER JOIN ODS_HRMASTER.EMPLOYEE E
ON L.EMPLOYEE_ID = E.EMPLOYEE#
LEFT OUTER JOIN ODS_PURE.PERSON_IDS T2
ON E.ID# = T2.VALUE
AND T2.TYPE = 'Employee ID';
Once you use the outer joined table's column in WHERE clause, It will result in the same result as inner join(there is another ways to use it in WHERE clause though). So it is better to avoid using outer joined table's column in the WHERE clause.
Try as
SELECT *
FROM ( (SELECT l.ENROLLED_CONTENT,
l.LEARNING_ENROLLMENT_LEARNER,
l.EMPLOYEE_ID,
l.JOB_FAMILY_GROUP,
l.EMPLOYEE_TYPE,
l.JOB_FAMILY,
l.LEARNING_ENROLLMENT,
l.COMPLETION_STATUS,
l.COMPLETION_DATE,
l.EXPIRATION_DATE,
l.CF_LRV_LEARNING_CONTENT_NUMBER,
l.LEARNING_CONTENT_DETAIL,
l.LEARNING_CONTENT_TYPE,
l.LESSON_TYPE,
e.id# "WK_WORKER_ID"
FROM tgt_workday.learning l
LEFT OUTER JOIN ods_hrmaster.employee e
ON l.EMPLOYEE_ID = e.employee) t1
LEFT OUTER JOIN
(SELECT per_ids_id, per_id, id_pureid FROM ods_pure.person_ids) t2
ON t1.wk_worker_id = t2.VAL AND t2.TYPE = 'Employee ID')

Column name is not passed to PostgreSQL on JDBC Scan in Apache Drill

While trying to run SQL query for PostgreSQL, instead of the column names from the table referred it it pushing down * to the database.
select
m.m_id,
cnt_c_no
from (
select
m_id
from pg_test_main.test1.table1
where
last_date >= '2019-01-01 00:00:00'
) as m
left join (
select
ci.m_id,
count(ci.c_no) as cnt_c_no
from (
select
m_id,
c_no
from pg_test.public.table2
) as ci
inner join (
select
c_no
from pg_test.public.table3
where
is_del = 'F'
) as c on ci.c_no = c.c_no
group by
ci.m_id
) as join1 on m.m_id = join1.m_id;
00-00 Screen
00-01 Project(m_id=[$0], cnt_c_no=[$1])
00-02 Project(m_id=[$0], cnt_c_no=[$2])
00-03 HashJoin(condition=[=($0, $1)], joinType=[left], semi-join: =[false])
00-05 Jdbc(sql=[SELECT "m_id" FROM "test1"."table1" WHERE "last_date" >= '2019-01-01 00:00:00' ])
00-04 Project(m_id0=[$0], cnt_c_no=[$1])
00-06 HashAgg(group=[{0}], cnt_c_no=[COUNT($1)])
00-07 Project(m_id=[$0], c_no=[$1])
00-08 HashJoin(condition=[=($1, $2)], joinType=[inner], semi-join: =[false])
00-10 Project(m_id=[$3], c_no=[$1])
00-12 Jdbc(sql=[SELECT * FROM "public"."table2" ])
00-09 Project(c_no0=[$0])
00-11 Project(c_no=[$0])
00-13 SelectionVectorRemover
00-14 Filter(condition=[=($60, 'F')])
00-15 Jdbc(sql=[SELECT * FROM "public"."table3" ])
As you can see, Jdbc Scan for table1 was using column names.
but, Jdbc Scan for table2 and table3 was not using column names. It pushed down * to the database.
How can I control jdbc scan so that it can push down colume names?
Apache Drill version is 1.16.0 (embedded-mode)
I tried to reproduce it with MySQL on both Drill 1.17 and Drill 1.15, but for the query, similar to the query you have specified, all the query is pushed into the JDBC storage:
SELECT m.person_id,
cnt_c_no
FROM
(SELECT person_id
FROM mysql.`drill_mysql_test1`.person1
WHERE date_field >= '2019-01-01 00:00:00') AS m
LEFT JOIN
(SELECT ci.person_id,
count(ci.last_name) AS cnt_c_no
FROM
(SELECT person_id,
last_name
FROM mysql.`drill_mysql_test`.person) AS ci
INNER JOIN
(SELECT last_name
FROM mysql.`drill_mysql_test`.person2
WHERE boolean_field = 'F' ) AS c ON ci.last_name = c.last_name
GROUP BY ci.person_id) AS join1 ON m.person_id = join1.person_id
The plan for this query:
00-00 Screen
00-01 Project(person_id=[$0], cnt_c_no=[$1])
00-02 Jdbc(sql=[SELECT `t0`.`person_id`, `t5`.`cnt_c_no` FROM (SELECT `person_id` FROM `drill_mysql_test1`.`person1` WHERE `date_field` >= '2019-01-01 00:00:00') AS `t0` LEFT JOIN (SELECT `t1`.`person_id`, COUNT(`t1`.`last_name`) AS `cnt_c_no` FROM (SELECT `person_id`, `last_name` FROM `drill_mysql_test`.`person`) AS `t1` INNER JOIN (SELECT `last_name` FROM `drill_mysql_test`.`person2` WHERE `boolean_field` = 'F') AS `t3` ON `t1`.`last_name` = `t3`.`last_name` GROUP BY `t1`.`person_id`) AS `t5` ON `t0`.`person_id` = `t5`.`person_id` ])
Could you please provide CTAS for Postgres tables, so I will try to reproduce it again with specific data types. Also, if possible, please check whether this issue is still reproduced on Drill 1.17.
UPD:
Comment under this answer helped to discover that this problem was caused by the following issue: https://issues.apache.org/jira/browse/DRILL-7340 and it will be resolved in Drill 1.18.0.

Only want to return rows that have duplicate unitid within group by unitid

I am working in SSRS querying against an oracle database.
So I have a data source and this report is supposed to find duplicate Work Orders based on multiple open workorders on a unique unitid. So I only want to show groups that have more then one entry as they are grouped by unitid.
SELECT
COMPSTSB.UNITID,
COMPSTSB.UNITTYPE,
ACTDEFN.ACTDESC,
ACTDEFN.ACTCODE,
HISTORY.WONO,
HISTORY.COMPFLAG,
HISTORY.ADDDTTM,
HISTORY.COMMENTS
FROM (IMSV7.COMPSTSB COMPSTSB INNER JOIN IMSV7.HISTORY HISTORY ON
COMPSTSB.COMPKEY=HISTORY.COMPKEY) INNER JOIN IMSV7.ACTDEFN ACTDEFN ON
HISTORY.ACTKEY=ACTDEFN.ACTKEY
WHERE HISTORY.COMPFLAG='Y' AND NOT (ACTDEFN.ACTCODE='DBR' OR ACTDEFN.ACTCODE='IN')
ORDER BY COMPSTSB.UNITTYPE, COMPSTSB.UNITID, HISTORY.ADDDTTM
Can anyone point me in the right direction? And yes before someone says this has been asked a million times, I did search. Point me to the million times and I will see if I feel they match my question. Ideally in the SQL I could make new column that returned a count of the unitid and I did attempt this but failed, and then I could filter on that column to remove any that only had one count. I really don't think this should be difficult but I have spent about 4 hours on it so far.
Thanks in advance!
Steven
If I understood your question right, the following should give you what's needed :
SELECT * FROM
(
SELECT
COMPSTSB.UNITID,
COMPSTSB.UNITTYPE,
ACTDEFN.ACTDESC,
ACTDEFN.ACTCODE,
HISTORY.WONO,
HISTORY.COMPFLAG,
HISTORY.ADDDTTM,
HISTORY.COMMENTS,
COUNT(1) OVER (PARTITION BY COMPSTSB.UNITID) AS numDups
FROM (IMSV7.COMPSTSB COMPSTSB INNER JOIN IMSV7.HISTORY HISTORY ON
COMPSTSB.COMPKEY=HISTORY.COMPKEY) INNER JOIN IMSV7.ACTDEFN ACTDEFN ON
HISTORY.ACTKEY=ACTDEFN.ACTKEY
WHERE HISTORY.COMPFLAG='Y' AND NOT (ACTDEFN.ACTCODE='DBR' OR ACTDEFN.ACTCODE='IN')
)a
WHERE a.numDups >1
ORDER BY COMPSTSB.UNITTYPE, COMPSTSB.UNITID, HISTORY.ADDDTTM
I expect you are concerned about having duplicate values of UNITID in the IMSV7.COMPSTSB table. If so adding this join to your query should enable ou to identify them:
JOIN (SELECT COMPSTSB.UNITID
FROM IMSV7.COMPSTSB
GROUP BY COMPSTSB.UNITID
HAVING COUNT(COMPSTSB.UNITID) > 1) dups
ON DUPS.UNITID = COMPSTSB.UNITID
JOIN IMSV7.HISTORY HISTORY
Here's the full query:
SELECT COMPSTSB.UNITID
, COMPSTSB.UNITTYPE
, ACTDEFN.ACTDESC
, ACTDEFN.ACTCODE
, HISTORY.WONO
, HISTORY.COMPFLAG
, HISTORY.ADDDTTM
, HISTORY.COMMENTS
FROM IMSV7.COMPSTSB COMPSTSB
JOIN (SELECT COMPSTSB.UNITID
FROM IMSV7.COMPSTSB
GROUP BY COMPSTSB.UNITID
HAVING COUNT(COMPSTSB.UNITID) > 1) dups
ON DUPS.UNITID = COMPSTSB.UNITID
JOIN IMSV7.HISTORY HISTORY
ON COMPSTSB.COMPKEY = HISTORY.COMPKEY
JOIN IMSV7.ACTDEFN ACTDEFN
ON HISTORY.ACTKEY = ACTDEFN.ACTKEY
WHERE HISTORY.COMPFLAG = 'Y'
AND ACTDEFN.ACTCODE NOT IN ('DBR','IN')
ORDER BY COMPSTSB.UNITTYPE
, COMPSTSB.UNITID
, HISTORY.ADDDTTM;
Since the above query didn't work you can try outer joins to similar sub queries on each of your tables and limit to only records where the outer joined table returns data. This will show you which tables in your query are cuasing your extra rows.:
SELECT COMPSTSB.UNITID
, COMPSTSB.UNITTYPE
, ACTDEFN.ACTDESC
, ACTDEFN.ACTCODE
, HISTORY.WONO
, HISTORY.COMPFLAG
, HISTORY.ADDDTTM
, HISTORY.COMMENTS
, DUPS.UNITID UNITID_DUP
, DUPS2.COMPKEY COMPKEY_DUP
, DUPS3.ACTKEY ACTKEY_DUP
FROM IMSV7.COMPSTSB COMPSTSB
JOIN IMSV7.HISTORY HISTORY
ON COMPSTSB.COMPKEY = HISTORY.COMPKEY
JOIN IMSV7.ACTDEFN ACTDEFN
ON HISTORY.ACTKEY = ACTDEFN.ACTKEY
LEFT JOIN (SELECT COMPSTSB.UNITID
FROM IMSV7.COMPSTSB
GROUP BY COMPSTSB.UNITID
HAVING COUNT(COMPSTSB.UNITID) > 1) dups
ON DUPS.UNITID = COMPSTSB.UNITID
LEFT JOIN (SELECT HISTORY.COMPKEY
FROM IMSV7.HISTORY
GROUP BY HISTORY.COMPKEY
HAVING COUNT(HISTORY.COMPKEY) > 1) dups2
ON DUPS.UNITID = COMPSTSB.UNITID
LEFT JOIN (SELECT ACTDEFN.ACTKEY
FROM IMSV7.ACTDEFN
GROUP BY ACTDEFN.ACTKEY
HAVING COUNT(ACTDEFN.ACTKEY) > 1) dups3
ON DUPS.UNITID = COMPSTSB.UNITID
WHERE HISTORY.COMPFLAG = 'Y'
AND ACTDEFN.ACTCODE NOT IN ('DBR','IN')
AND ( DUPS.UNITID IS NOT NULL OR
DUPS2.COMPKEY IS NOT NULL OR
DUPS3.ACTKEY IS NOT NULL)
ORDER BY COMPSTSB.UNITTYPE
, COMPSTSB.UNITID
, HISTORY.ADDDTTM;

Assistance replacing oracle (+) joins to ANSI joins

I've reviewed other posts as well as Oracle documentation on replacing the older style (+) joins with ANSI format joins. I'm having a hard time converting this over to what I assume to be two left outer join operations. My hangup is the two from select statements and where exactly the joins should be placed.
Here is my query:
SELECT
AUP.USERNAME,
AUP.MENU_STRING MODULE,
NVL(UGA.PERMISSION,AUP.DEFAULT_PERMISSION) PERMISSION
FROM
(SELECT
DU.USERNAME,
A.PROGRAM_ID,
A.MENU_STRING,
'Y' DEFAULT_PERMISSION
FROM
APPLICATION A,
DBA_USERS DU
WHERE
A.PROGRAM_ID NOT IN ('.SEPARATOR')
AND DU.USERNAME NOT LIKE '%#') AUP,
(SELECT
USER_ID,
PROGRAM_ID,
PERMISSION
FROM
USER_PGM_AUTHORITY
WHERE
PROGRAM_COMPONENT='PROGRAM') UGA
WHERE
AUP.USERNAME=UGA.USER_ID(+)
AND AUP.PROGRAM_ID=UGA.PROGRAM_ID(+)
AND aup.menu_string = 'Vendor Maintenance'
ORDER BY
AUP.USERNAME,
AUP.MENU_STRING;
I think this will do it:
SELECT
AUP.USERNAME,
AUP.MENU_STRING MODULE,
NVL(UGA.PERMISSION,AUP.DEFAULT_PERMISSION) PERMISSION
FROM
(SELECT
DU.USERNAME,
A.PROGRAM_ID,
A.MENU_STRING,
'Y' DEFAULT_PERMISSION
FROM
APPLICATION A,
DBA_USERS DU
WHERE
A.PROGRAM_ID NOT IN ('.SEPARATOR')
AND DU.USERNAME NOT LIKE '%#') AUP
LEFT JOIN
(SELECT
USER_ID,
PROGRAM_ID,
PERMISSION
FROM
USER_PGM_AUTHORITY
WHERE
PROGRAM_COMPONENT='PROGRAM') UGA
ON
AUP.USERNAME=UGA.USER_ID
AND AUP.PROGRAM_ID=UGA.PROGRAM_ID
WHERE
aup.menu_string = 'Vendor Maintenance'
ORDER BY
AUP.USERNAME,
AUP.MENU_STRING;
The join is between AUPand UGA:
SELECT
AUP.USERNAME,
AUP.MENU_STRING MODULE,
NVL(UGA.PERMISSION,AUP.DEFAULT_PERMISSION) PERMISSION
FROM
(SELECT
DU.USERNAME,
A.PROGRAM_ID,
A.MENU_STRING,
'Y' DEFAULT_PERMISSION
FROM
APPLICATION A,
DBA_USERS DU
WHERE
A.PROGRAM_ID NOT IN ('.SEPARATOR')
AND DU.USERNAME NOT LIKE '%#') AUP
LEFT JOIN
(SELECT
USER_ID,
PROGRAM_ID,
PERMISSION
FROM
USER_PGM_AUTHORITY
WHERE
PROGRAM_COMPONENT='PROGRAM') UGA
ON AUP.USERNAME=UGA.USER_ID
AND AUP.PROGRAM_ID=UGA.PROGRAM_ID
WHERE aup.menu_string = 'Vendor Maintenance'
ORDER BY
AUP.USERNAME,
AUP.MENU_STRING;
You can refactor it using named sub-queries to make it more readable:
WITH AUP AS ( -- Moved to a named sub-query
SELECT
DU.USERNAME,
A.PROGRAM_ID,
A.MENU_STRING,
'Y' DEFAULT_PERMISSION
FROM
APPLICATION A
CROSS JOIN -- No apparent join condition so used an explicit CROSS JOIN.
DBA_USERS DU
WHERE
A.PROGRAM_ID NOT IN ('.SEPARATOR')
AND DU.USERNAME NOT LIKE '%#'
AND A.MENU_STRING = 'Vendor Maintenance' -- Moved to the appropriate sub-query
),
UGA AS ( -- Moved to a named sub-query
SELECT
USER_ID,
PROGRAM_ID,
PERMISSION
FROM
USER_PGM_AUTHORITY
WHERE
PROGRAM_COMPONENT='PROGRAM'
)
SELECT
AUP.USERNAME,
AUP.MENU_STRING MODULE,
NVL(UGA.PERMISSION,AUP.DEFAULT_PERMISSION) PERMISSION
FROM
AUP
LEFT OUTER JOIN
UGA
ON ( AUP.USERNAME =UGA.USER_ID
AND AUP.PROGRAM_ID=UGA.PROGRAM_ID )
ORDER BY
AUP.USERNAME,
AUP.MENU_STRING;
Borrowing this thread from 10 years ago. I've tried to adapt the solution to my query but I can't figure it out.
Here is my query and I want to replace the (+) with LEFT JOIN
FROM a,b,c
WHERE b.a = '101'
AND a.a = '202'
AND b.c = a.c
AND a.d = c.d(+)
AND ROWNUM = 1;

Oracle : How to use if then in a select statement

select ma.TITLE,ma.ID as aid,ur.USER_ID
from LEO_MENU_ACTIVITY_RELATION mr
inner join LEO_MENU_MASTER mm on mm.ID=mr.MENU_ID
INNER join LEO_MENUACTIVITY ma on mr.ACTIVITY_ID=ma.ID
LEFT OUTER JOIN LEO_USER_RIGHTS ur on ma.ID=ur.MENU_RELATION_ID and ur.MENU_ID=mm.ID and ur.USER_ID='141'
where mm.ID='1'
UNION (SELECT
'List' as TITLE,
1 as ID,
case (WHEN ur.MENU_RELATION_ID=1 THEN NULL ELSE USER_ID END)as USER_ID
from
LEO_USER_RIGHTS)
In the UNION i want perform a conditional select like if ur.MENU_RELATION_ID=1 then the USER_ID should be selected as NULL otherwise the the original value from the 'LEO_USER_RIGHTS' table must be retrieved.
How can i do this ? Please help
Krishnik
If you want to combine in a UNION something based on the first table I think you can only do it by repeating the whole thing like this:
select ma.TITLE,ma.ID as aid,ur.USER_ID
from LEO_MENU_ACTIVITY_RELATION mr
inner join LEO_MENU_MASTER mm on mm.ID=mr.MENU_ID
INNER join LEO_MENUACTIVITY ma on mr.ACTIVITY_ID=ma.ID
LEFT OUTER JOIN LEO_USER_RIGHTS ur on ma.ID=ur.MENU_RELATION_ID and ur.MENU_ID=mm.ID and ur.USER_ID='141'
where mm.ID='1'
UNION (SELECT
'List' as TITLE,
1 as ID,
case (WHEN ur.MENU_RELATION_ID=1 THEN NULL ELSE USER_ID END)as USER_ID
from
LEO_MENU_ACTIVITY_RELATION mr
inner join LEO_MENU_MASTER mm on mm.ID=mr.MENU_ID
INNER join LEO_MENUACTIVITY ma on mr.ACTIVITY_ID=ma.ID
LEFT OUTER JOIN LEO_USER_RIGHTS ur on ma.ID=ur.MENU_RELATION_ID and ur.MENU_ID=mm.ID and ur.USER_ID='141'
where mm.ID='1'
)
If this is used often I would create a view to avoid duplicate code. In ORACLE (I do not know for other SQL dialects) there is a WITH statement enables you to make a sort of "temporary view".

Resources