How to Use Case statement in Left outer Join using Operator +? - sql

Query:
select /*+ full(c)parallel(c,4) */ a.*
from ioct_inv_item_all a,
(select udac_group_name, function_order , db_region, workflow_type, change_level
from ioct_function_target
where udac_group_name = 'Banner'
and function_name = 'emptyParam'
and workflow_type = 'CHGFCLTR'
and ('emptyParam' = 'emptyParam' or ('CHGFCLTR' != 'NEWITM' AND change_level = 'emptyParam') or ('CHGFCLTR' = 'NEWITM' and change_level = 'Simple') )
and sysdate between effective_from_date and effective_to_date ) b , item_ca c ,product_ca d,assignment_ca ac ,branches b
where a.udac_group_name = 'Banner'
and a.workflow_type = 'CHGFCLTR'
and a.DB_REGION = b.db_region (+)
and a.workflow_type = b.workflow_type (+)
and a.udac_group_name = b.udac_group_name (+)
and a.change_level = b.change_level (+)
and a.product_code = c.product_code(+)
and a.product_issue_num = c.product_issue_num(+)
and a.item_id = c.item_id(+)
and a.customer_id = c.customer_id(+)
and c.product_code = d.product_code(+)
and c.product_issue_num = d.product_issue_num(+)
and c.product_issue_year = d.product_issue_year(+)
and c.customer_id = d.customer_id(+)
and (case when c.contract_assignment_id IS NOT NULL
AND c.contract_assignment_id > 0
THEN c.contract_assignment_id
ELSE d.regular_assign_id
END) = ac.assignment_id(+)
and ('emptyParam' = 'emptyParam' OR ('CHGFCLTR' = 'NEWITM' AND a.eue_normal_ind = 'emptyParam') OR ('CHGFCLTR' != 'NEWITM' AND a.change_level = 'emptyParam') )
and (('emptyParam') IN ('emptyParam') OR a.region IN ('emptyParam'))
and ('emptyParam' = 'emptyParam'
OR (b.function_order is not null and a.assignee_group_seq = b.function_order)
OR (b.function_order is null and 'emptyParam' = 'emptyParam')
Error:
error:
ORA-01417: a table may be outer joined to at most one other table
01417. 00000 - "a table may be outer joined to at most one other table"
*Cause: a.b (+) = b.b and a.c (+) = c.c is not allowed
*Action: Check that this is really what you want, then join b and c first
in a view.
Error at Line: 28 Column: 20
Does any body suggest any alternative to do same thing without using keyword LEFT OUTER JOIN because i do not want to change the structure of sql query already Written?

The basic idea is that you start with a driving table and then outer join it to other tables. If a is your driving table, then
select x
from a,b,c
where a.x = b.x(+)
and a.y = c.y(+)
is the sort of query oracle expects in the join.
If you really want outer join a table with multiple "driving" tables, you can to use a syntax like this, as pointed out in the error description
Assuming you want to outer join "a" to both "b" and "c"
select *
from a,
(select *
from a,c
where c.y = a.y(+)
)
where b.x = a.x(+)
;

Related

SQL WHERE statement returning both or conditions

I'm trying to return a single row based on this where statement
WHERE
(C.id = G.community_id
AND P.service_type_id = G.service_type_id
AND I.unit_class_id = G.unit_class_id)
OR
(C.id = G.community_id
AND P.service_type_id = G.service_type_id)
The issue is I have to get a row based on multiple criteria and the more that match determines the final match. The statement above returns a row just fine if it matches the bottom or statement, but if it matches the first OR it returns results for both statements.
LIMIT 1 doesn't work either as sometimes it gives preference to the wrong result.
EDIT:
community_id
service_type_id
unit_class_id
1
1
1
1
1
null
Because of the way the table is both rows are true, my understanding was SQL took the first one that was true and returned it.
I apologize for not a lot of info I was hoping maybe there was just a bit of info I was missing. Here is my query.
CREATE VIEW view_invoice_line_item_gl_code
AS
SELECT
DISTINCT(ILI.invoice_line_item_id) AS invoice_line_item_id,
C.community_id AS community_id,
S.service_type_id AS service_type_id,
U.unit_class_id AS unit_class_id,
LIP.line_item_provider_id AS line_item_provider_id,
(SELECT gl_code_id
FROM gl_code G
WHERE (C.community_id = G.community_id
AND P.service_type_id = G.service_type_id)
AND ((G.unit_class_id IS NULL
AND G.line_item_provider_id IS NULL)
OR
(I.unit_class_id = G.unit_class_id
AND G.line_item_provider_id IS NULL)
OR
(I.unit_class_id = G.unit_class_id
AND ILI.line_item_provider_id = G.line_item_provider_id)
)) AS gl_code_id
FROM
invoice I
JOIN
invoice_line_item ILI ON (ILI.invoice_id = I.invoice_id)
JOIN
invoice_header IH ON (I.invoice_header_id = IH.invoice_header_id)
JOIN
provider_community_account PC ON (I.provider_community_account_id = PC.provider_community_account_id)
JOIN
line_item_provider LIP ON (ILI.line_item_provider_id = LIP.line_item_provider_id)
JOIN
unit_class U ON (I.unit_class_id = U.unit_class_id)
JOIN
community C ON (PC.community_id = C.community_id)
JOIN
provider P ON (PC.provider_id = P.provider_id)
JOIN
service_type S ON (P.service_type_id = S.service_type_id)
I'm assuming that you want to get the record that matches the most conditions first. One way to do that is to order by the number of matching conditions (in this case only one condition is different):
SELECT TOP 1 ...
FROM ...
WHERE
C.id = G.community_id
AND P.service_type_id = G.service_type_id
ORDER BY CASE WHEN I.unit_class_id = G.unit_class_id THEN 1 ELSE 0 END DESC
The first condition implies the second, so you can simplify it like this:
WHERE
C.id = G.community_id
AND P.service_type_id = G.service_type_id
You say where (A AND B) OR A so where A is sufficient.
You'll need to compute a "score" somehow. If you consider each predicate awards 1 point, then you could do something like:
select *
from (
select *,
case when <predicate1> then 1 else 0 end +
case when <predicate2> then 1 else 0 end as score
from t
WHERE
(C.id = G.community_id
AND P.service_type_id = G.service_type_id
AND I.unit_class_id = G.unit_class_id
)
OR
(
C.id = G.community_id
AND P.service_type_id = G.service_type_id
)
)
ORDER BY score DESC
LIMIT 1

Unsure why ORA-00918 column ambiguously defined is appearing

I'm unsure as to why I'm getting the ORA-00918 error message appearing when I type in the following code.
I can't see which column is ambiguously defined.
What I want to do is create a table that pulls in the b.site_code value based on the work_header_no, work_version_no and site_numbers matching in queries A & B matching.
Code is below
SELECT
a.statement.statement_date,
a.sw_header.organise_code,
a.organisation.organise_name,
a.PermitRef,
a.actual_inspection.logged_time,
a.insp_category.insp_category_name,
a.actual_inspection.insp_number,
a.actual_inspection.site_number,
a.inspection_outcome.insp_outcome_name,
a.insp_category.insp_charge,
a.actual_inspection.insp_notes,
a.actual_inspection.work_header_no,
a.actual_inspection.insp_time,
b.site_code
FROM
(select
statement.statement_date,
sw_header.organise_code,
organisation.organise_name,
CAST(
organisation.external_ref_2 ||''||
sw_header.works_ref||'.'||
sw_notice_header.app_seq_no||'.'||
sw_notice_header.ext_version_no
as VARCHAR (40)) as PermitRef,
actual_inspection.logged_time,
insp_category.insp_category_name,
actual_inspection.insp_number,
actual_inspection.site_number,
inspection_outcome.insp_outcome_name,
insp_category.insp_charge,
actual_inspection.insp_notes,
actual_inspection.work_header_no,
actual_inspection.insp_time,
sw_notice_header.work_header_no,
sw_notice_header.work_version_no,
actual_inspection.site_number
from
actual_inspection
inner join sw_header on
actual_inspection.work_header_no = sw_header.work_header_no
inner join sw_notice_header on
sw_header.work_header_no = sw_notice_header.work_header_no
and sw_header.work_version_no = sw_notice_header.work_version_no
inner join insp_category on
actual_inspection.insp_category_code = insp_category.insp_category_code
inner join inspection_outcome on
actual_inspection.insp_outcome_code = inspection_outcome.insp_outcome_code
inner join organisation on
sw_header.organise_code = organisation.organise_code
inner join statement on
organisation.organise_code = statement.organise_code
and organisation.statement_number = statement.statement_no
where
actual_inspection.notice_type_code = '2600' and
actual_inspection.insp_outcome_code != 'O40'
order by
actual_inspection.logged_time)
a
JOIN
(
select
sns.work_header_no,
sns.work_version_no,
sns.site_number,
sns.site_code
from
sw_notice_site sns
)
b
ON a.work_header_no = b.work_header_no and
a.work_version_no = b.work_version_no and
a.site_number = b.site_number
You have duplicate actual_inspection.site_number and work_header_no remove the duplicate rows
actual_inspection.site_number,
inspection_outcome.insp_outcome_name,
insp_category.insp_charge,
actual_inspection.insp_notes,
actual_inspection.work_header_no,
actual_inspection.insp_time,
sw_notice_header.work_header_no,
sw_notice_header.work_version_no,
actual_inspection.site_number
No need to use a.statement.statement_date. You can use a.statement_date.
Likewise change all other columns for a..
Your whole query should look like this:
SELECT -- removed table names from all the columns
A.STATEMENT_DATE,
A.ORGANISE_CODE,
A.ORGANISE_NAME,
A.PERMITREF,
A.LOGGED_TIME,
A.INSP_CATEGORY_NAME,
A.INSP_NUMBER,
A.SITE_NUMBER,
A.INSP_OUTCOME_NAME,
A.INSP_CHARGE,
A.INSP_NOTES,
A.WORK_HEADER_NO,
A.INSP_TIME,
B.SITE_CODE
FROM
(
SELECT
STATEMENT.STATEMENT_DATE,
SW_HEADER.ORGANISE_CODE,
ORGANISATION.ORGANISE_NAME,
CAST(ORGANISATION.EXTERNAL_REF_2
|| ''
|| SW_HEADER.WORKS_REF
|| '.'
|| SW_NOTICE_HEADER.APP_SEQ_NO
|| '.'
|| SW_NOTICE_HEADER.EXT_VERSION_NO AS VARCHAR(40)) AS PERMITREF,
ACTUAL_INSPECTION.LOGGED_TIME,
INSP_CATEGORY.INSP_CATEGORY_NAME,
ACTUAL_INSPECTION.INSP_NUMBER,
--ACTUAL_INSPECTION.SITE_NUMBER, -- commented this as it is there in statement twice
INSPECTION_OUTCOME.INSP_OUTCOME_NAME,
INSP_CATEGORY.INSP_CHARGE,
ACTUAL_INSPECTION.INSP_NOTES,
ACTUAL_INSPECTION.WORK_HEADER_NO,
ACTUAL_INSPECTION.INSP_TIME,
--SW_NOTICE_HEADER.WORK_HEADER_NO, -- commented this as it is there in statement twice
SW_NOTICE_HEADER.WORK_VERSION_NO,
ACTUAL_INSPECTION.SITE_NUMBER
FROM
ACTUAL_INSPECTION
INNER JOIN SW_HEADER ON ACTUAL_INSPECTION.WORK_HEADER_NO = SW_HEADER.WORK_HEADER_NO
INNER JOIN SW_NOTICE_HEADER ON SW_HEADER.WORK_HEADER_NO = SW_NOTICE_HEADER.WORK_HEADER_NO
AND SW_HEADER.WORK_VERSION_NO = SW_NOTICE_HEADER.WORK_VERSION_NO
INNER JOIN INSP_CATEGORY ON ACTUAL_INSPECTION.INSP_CATEGORY_CODE = INSP_CATEGORY.INSP_CATEGORY_CODE
INNER JOIN INSPECTION_OUTCOME ON ACTUAL_INSPECTION.INSP_OUTCOME_CODE = INSPECTION_OUTCOME.INSP_OUTCOME_CODE
INNER JOIN ORGANISATION ON SW_HEADER.ORGANISE_CODE = ORGANISATION.ORGANISE_CODE
INNER JOIN STATEMENT ON ORGANISATION.ORGANISE_CODE = STATEMENT.ORGANISE_CODE
AND ORGANISATION.STATEMENT_NUMBER = STATEMENT.STATEMENT_NO
WHERE
ACTUAL_INSPECTION.NOTICE_TYPE_CODE = '2600'
AND ACTUAL_INSPECTION.INSP_OUTCOME_CODE != 'O40'
ORDER BY
ACTUAL_INSPECTION.LOGGED_TIME
) A
JOIN (
SELECT
SNS.WORK_HEADER_NO,
SNS.WORK_VERSION_NO,
SNS.SITE_NUMBER,
SNS.SITE_CODE
FROM
SW_NOTICE_SITE SNS
) B ON A.WORK_HEADER_NO = B.WORK_HEADER_NO
AND A.WORK_VERSION_NO = B.WORK_VERSION_NO
AND A.SITE_NUMBER = B.SITE_NUMBER;
Cheers!!

Using a REPLACE function in a SELECT CASE query

I am writing a script where the cable_no is the foreign key to the other tables that I will be joining.
An example of the cable_no may look like this "A01234567B". However, the cable_no in other tables is "A01234567" (basically its the same record without the B at the end)
How do I construct my script such that I remove all the "B" in the cable_no before joining to other tables?
select cc.riser_fid as RISER_FID, cc.cbl_fid as ZH_CBL_FID, f.cable_no AS ZH_CBL_NAME, FM.FACILITY_ID as FACILITY_ID, FC.CHANNEL_ID AS CHANNEL_ID,
ft.FACILITY_TRAIL_ITM_ID AS FACILITY_TRAIL_ITM_ID, ft2.parent_fac_trl_itm_id as parent_fac_trl_itm_id, FT2.TRAIL_SEQ_NO, FT2.A_SITE_ID, ft2.asgn_channel_id,
CASE WHEN
F.CABLE_NO LIKE '%B' REPLACE('B', '')
,CASE
WHEN ft2.a_site_id = a.a_site_id then 1
else null
END EXIST_IN_GTECH
from sgtel10.connected_cables cc
JOIN gc_fcbl_temp f on f.g3e_fid = cc.cbl_fid AND f.ltt_id in (0,888888888)
JOIN FACILITY_MASTER_TEMP FM ON FM.FACILITY_NAME = f.cable_no
JOIN FACILITY_CHANNEL_TEMP FC ON FC.FACILITY_ID = FM.FACILITY_ID AND FC.CHANNEL_ID IS NOT NULL
JOIN FACILITY_TRAIL_ITEMS_TEMP ft on ft.facility_trail_itm_id = fc.facility_trail_itm_id
JOIN FACILITY_TRAIL_ITEMS_TEMP ft2 on ft2.parent_fac_trl_itm_id = ft.parent_fac_trl_itm_id and ft2.trail_seq_no = 1.0
LEFT JOIN A_SITE_ID A ON A.A_SITE_ID = FT2.A_SITE_ID)
;
You can do something like this:
t1 join
t2
on t1.cable_no = t2.cable_no || 'B'
|| is the standard operator for string concatenation.

Error Position: 27 Return: 1730 - ORA-01730: invalid number of column names specified

I need help in creating a view in PeopleSoft using PeopleTools Application Designer. When running the view SQL below in ORACLE SQL Developer, it selects perfectly fine but when I create it as view in App Designer I get the error below:
Error: UM_7902_VW - SQL Error. Error Position: 27 Return: 1730 - ORA-01730: invalid number of column names specified.
Here is my sql:
SELECT A.EMPLID, B.NAME, A.ADM_APPL_NBR, C.ADMIN_FUNCTION, A.STDNT_CAR_NBR,
A.ACAD_CAREER, D.APPL_PROG_NBR, D.ADMIT_TERM, C.CHECKLIST_CD, E.DESCRSHORT,
C.CHECKLIST_STATUS, C.STATUS_DT, C.DUE_DT AS C_DUE_DT, C.COMM_COMMENTS,
C.SEQ_3C, F.CHKLST_ITEM_CD,
G.DESCR, F.ITEM_STATUS, F.STATUS_DT, F.DUE_DT AS F_DUE_DT, F.RESPONSIBLE_ID
FROM PS_ADM_APPL_DATA A
JOIN PS_PERSON_NAME B ON B.EMPLID = A.EMPLID
JOIN PS_PERSON_CHECKLST C ON C.COMMON_ID = A.EMPLID
JOIN PS_ADM_APPL_PROG D ON D.EMPLID = A.EMPLID
AND D.EMPLID = A.EMPLID
AND D.ACAD_CAREER= A.ACAD_CAREER
AND D.STDNT_CAR_NBR= A.STDNT_CAR_NBR
AND D.ADM_APPL_NBR= A.ADM_APPL_NBR
AND D.EFFDT =
(SELECT MAX(D2.EFFDT) FROM PS_ADM_APPL_PROG D2
WHERE D.EMPLID = D2.EMPLID
AND D.ACAD_CAREER = D2.ACAD_CAREER
AND D.STDNT_CAR_NBR = D2.STDNT_CAR_NBR
AND D.ADM_APPL_NBR = D2.ADM_APPL_NBR
AND D.APPL_PROG_NBR = D2.APPL_PROG_NBR
AND D2.EFFDT <= SYSDATE)
AND D.EFFSEQ =
(SELECT MAX(D3.EFFSEQ) FROM PS_ADM_APPL_PROG D3
WHERE D.EMPLID = D3.EMPLID
AND D.ACAD_CAREER = D3.ACAD_CAREER
AND D.STDNT_CAR_NBR = D3.STDNT_CAR_NBR
AND D.ADM_APPL_NBR = D3.ADM_APPL_NBR
AND D.APPL_PROG_NBR = D3.APPL_PROG_NBR
AND D.EFFDT <= D3.EFFDT)
JOIN PS_CS_CHKLST_TBL E ON E.CHECKLIST_CD = C.CHECKLIST_CD
AND E.EFFDT = (SELECT MAX(E2.EFFDT) FROM PS_CS_CHKLST_TBL E2 WHERE
E2.INSTITUTION = E.INSTITUTION AND E2.CHECKLIST_CD = E.CHECKLIST_CD)
AND E.EFF_STATUS = 'A'
JOIN PS_PERSON_CHK_ITEM F ON F.COMMON_ID = C.COMMON_ID
AND F.SEQ_3C = C.SEQ_3C
JOIN PS_SCC_CKLSITM_TBL G ON G.CHKLST_ITEM_CD = F.CHKLST_ITEM_CD
AND G.EFF_STATUS = 'A'
AND G.EFFDT = (SELECT MAX(G2.EFFDT) FROM PS_SCC_CKLSITM_TBL G2 WHERE
G2.CHKLST_ITEM_CD = G.CHKLST_ITEM_CD)
JOIN PS_TERM_TBL H ON H.INSTITUTION = E.INSTITUTION
AND H.ACAD_CAREER = A.ACAD_CAREER
I would appreciate any help i can get. Thanks!
In App Designer when modeling the record: do you have an equal amount of fields in the record definition as you have in your select SQL?
These must match, otherwise this error appears when building in App Designer.
It looks as if you took create view some_view (col1, col2, ..., coln) as from one of its previous incarnations, modified the select statement you posted (added or removed some columns) and - once you stick it together - number of columns doesn't match any more.
The simplest way out of it is to let Oracle do it, i.e. don't name columns:
create view some_view as
select <your select goes here>
Though, pay attention to column names select returns; you can't have something like
select max(some_value), --> this - must have an alias
my_name
because columns query returns must have their aliases.

issue in converting oracle join query to ansi syntax

I am trying to convert the below mentioned query to ansi format
oracle query :
SELECT *
FROM table_1 a,
table_2 b,
table_2 c
WHERE c.dt(+) = a.dt
AND c.ap_no(+) = a.ap_no
AND c.jy_no(+) = a.jy_no
AND c.tn(+) = a.tn
AND b.dt(+) = a.dt
AND b.ap_no(+) = a.ap_no
AND b.jy_no(+) = a.jy_no
AND ( b.t_no(+) + 1 ) = a.t_no --> unable to understand this part
AND ( b.type_cd(+) = 100
AND c.type_cd(+) = 200);
ansi format :
select * from
table2 c right outer join table1 a on
c.dt = a.dt
and c.ap_no = a.ap_no
and c.jy_no = a.jy_no
and c.tn = a.tn
left outer join table2 b on
a.dt = b.dt
and a.ap_no = b.ap_no
and a.jy_no = b.jy_no
and a.t_no = b.t_no ------------------> wrongly implemented it
where b.type_cd = 100 and c.type_cd = 200;
I am not understanding, how to convert the +1 found in the "unable to understand this part" of the Oracle query to the ansi format. Please advise.
Edit : this is not fully similar to the problem explained here . I am just trying to understand the +1 part of the query.