JOIN Issue : Correct the SQL Statement to solve : ORA-01799: a column may not be outer-joined to a subquery - sql

As you see below; how can I implement fx.ftf_validitystartdate= ... this lines value since oracle does not allow me to do it like this below
.
select * from acc_accounts acc
join kp_paramcore p on
acc.account_no = p.accountnum
acc.suffix = p.suffixc
LEFT JOIN ftf_rates fx
ON p.maturestart = fx.ftf_vadealtsinir
AND p.maturefinish = fx.ftf_vadeustsinir
AND fx.statusrec = 'A'
AND fx.currencycode = acc.currencsw_kod
AND fx.status= 'A'
and fx.ftf_validitystartdate= (SELECT MAX(ff.ftf_validitystartdate)
FROM ftf_rates ff
WHERE ff.status = 'A'
AND ff.statusrec = 'A'
AND v_CurrentDate BETWEEN ff.systemstartdate AND ff.systemfinishdate AND ff.currencycode = acc.currencsw_kod
)

It should work if you switch this to a where clause:
select *
from acc_accounts acc join
kp_paramcore p
on acc.account_no = p.accountnum and
acc.suffix = p.suffixc LEFT JOIN
ftf_rates fx
ON p.maturestart = fx.ftf_vadealtsinir and
p.maturefinish = fx.ftf_vadeustsinir and
fx.statusrec = 'A' and
fx.currencycode = acc.currencsw_kod and
fx.status= 'A'
where fx.ftf_validitystartdate= (SELECT MAX(ff.ftf_validitystartdate)
FROM ftf_rates ff
WHERE ff.status = 'A' and
ff.statusrec = 'A'
p.v_CurrentDate BETWEEN ff.systemstartdate AND ff.systemfinishdate AND ff.currencycode = acc.currencsw_kod
)
However, you lose the 'left outer join' characteristics, so you would also want to add: or fx.ftf_validitystartdate is null. I guess that v_CurrentDate comes from "p". It is always a good idea to use table aliases before column names.
However, I question whether the subquery is really needed. It is only needed when there is more than one record that meets the conditions inside the subquery. Otherwise, I think you can just change the on clause to be:
ON p.maturestart = fx.ftf_vadealtsinir and
p.maturefinish = fx.ftf_vadeustsinir and
fx.statusrec = 'A' and
fx.currencycode = acc.currencsw_kod and
fx.status= 'A'and
p.v_CurrentDate BETWEEN fx.systemstartdate AND fx.systemfinishdate

I publish the workaround with CTE and tested only in Oracle 11g.
To make test I create this schema:
create table t_a ( a int );
create table t_b ( a int);
create table t_c ( a int);
insert into t_a values (1);
insert into t_a values (2);
insert into t_a values (3);
insert into t_b values (1);
insert into t_b values (2);
insert into t_b values (3);
insert into t_c values (1);
insert into t_c values (2);
insert into t_c values (3);
At this time I force error with this query:
select *
from t_a
left outer join t_b
on t_a.a = t_b.a and
t_b.a = ( select max( a )
from t_c);
And now I rewrite query with CTE:
with cte (a ) as (
select a
from t_b
where t_b.a = ( select min( a )
from t_c)
)
select *
from t_a
left outer join cte
on t_a.a = cte.a;
This second query returns right results.
I rewrite your query with CTE:
with CTE as (
select * from ftf_rates
where ftf_validitystartdate= (SELECT MAX(ff.ftf_validitystartdate)
FROM ftf_rates ff
WHERE ff.status = 'A'
AND ff.statusrec = 'A'
AND v_CurrentDate BETWEEN ff.systemstartdate
AND ff.systemfinishdate
AND ff.currencycode = acc.currencsw_kod )
)
select * from acc_accounts acc
join kp_paramcore p on
acc.account_no = p.accountnum
acc.suffix = p.suffixc
LEFT JOIN CTE fx
ON p.maturestart = fx.ftf_vadealtsinir
AND p.maturefinish = fx.ftf_vadeustsinir
AND fx.statusrec = 'A'
AND fx.currencycode = acc.currencsw_kod
AND fx.status= 'A'
Notice, only tested in Oracle 11g. See #a_horse_with_no_name coment:
#danihp: CTEs were available long before Oracle 11g (I think they were
introducted in 9.1 maybe even earlier - but they are definitely
available in 10.x). 11.2 introduced recursive CTEs which is not needed
in this case. –

Related

How to prevent insert if same records are present in the table

I have a query
INSERT INTO FCC_CS_WL_SOURCE_REQUEST_ID_MAP
(
"N_WL_SOURCE_REQUEST_ID",
"V_SOURCE_REQUEST_ID",
"V_TARGET_KEY",
"V_TARGET_INDEXNAME"
)
SELECT
MAP_SEQ_TEST.nextval,
FCC_CUST_DIM.V_ALT_CUST_ID AS "V_SOURCE_REQUEST_ID",
FCC_CS_MATCHED_RESULT_BULK.V_TARGET_KEY ,
FCC_CS_MATCHED_RESULT_BULK.V_TARGET_INDEXNAME
FROM FCC_CS_MATCHED_RESULT_BULK INNER JOIN FCC_CUST_DIM
ON FCC_CS_MATCHED_RESULT_BULK.V_SOURCE_KEY =FCC_CUST_DIM.V_CUST_INTRL_ID
AND FCC_CUST_DIM.F_LRI_FL ='Y'
AND FCC_CUST_DIM.V_ALT_CUST_ID IS NOT NULL
AND FCC_CS_MATCHED_RESULT_BULK.N_RUN_SKEY =290
Here I need to prevent the insert into FCC_CS_WL_SOURCE_REQUEST_ID_MAP table if V_SOURCE_REQUEST_ID,V_TARGET_KEY,V_TARGET_INDEXNAME columns values is already available with same value which is going to be inserted
How to modify this query to achieve that .?
Use a MERGE statement:
MERGE INTO FCC_CS_WL_SOURCE_REQUEST_ID_MAP dst
USING (
SELECT d.V_ALT_CUST_ID,
b.V_TARGET_KEY ,
b.V_TARGET_INDEXNAME
FROM FCC_CS_MATCHED_RESULT_BULK b
INNER JOIN FCC_CUST_DIM d
ON b.V_SOURCE_KEY = d.V_CUST_INTRL_ID
AND d.F_LRI_FL ='Y'
AND d.V_ALT_CUST_ID IS NOT NULL
AND b.N_RUN_SKEY =290
) src
ON (
src.V_ALT_CUST_ID = dst.V_SOURCE_REQUEST_ID
AND src.V_TARGET_KEY = dst.V_TARGET_KEY
AND src.V_TARGET_INDEXNAME = dst.V_TARGET_INDEXNAME
)
WHEN NOT MATCHED THEN
INSERT (
N_WL_SOURCE_REQUEST_ID,
V_SOURCE_REQUEST_ID,
V_TARGET_KEY,
V_TARGET_INDEXNAME
) VALUES (
MAP_SEQ_TEST.nextval,
src.V_ALT_CUST_ID,
src.V_TARGET_KEY,
src.V_TARGET_INDEXNAME
);
Add a NOT EXISTS clause in your SELECT:
INSERT INTO FCC_CS_WL_SOURCE_REQUEST_ID_MAP
(
"N_WL_SOURCE_REQUEST_ID",
"V_SOURCE_REQUEST_ID",
"V_TARGET_KEY",
"V_TARGET_INDEXNAME"
)
SELECT
MAP_SEQ_TEST.nextval,
FCC_CUST_DIM.V_ALT_CUST_ID AS "V_SOURCE_REQUEST_ID",
FCC_CS_MATCHED_RESULT_BULK.V_TARGET_KEY ,
FCC_CS_MATCHED_RESULT_BULK.V_TARGET_INDEXNAME
FROM FCC_CS_MATCHED_RESULT_BULK INNER JOIN FCC_CUST_DIM
ON FCC_CS_MATCHED_RESULT_BULK.V_SOURCE_KEY =FCC_CUST_DIM.V_CUST_INTRL_ID
AND FCC_CUST_DIM.F_LRI_FL ='Y'
AND FCC_CUST_DIM.V_ALT_CUST_ID IS NOT NULL
AND FCC_CS_MATCHED_RESULT_BULK.N_RUN_SKEY =290
AND NOT EXISTS (SELECT 1 FROM FCC_CS_WL_SOURCE_REQUEST_ID_MAP t1 WHERE V_SOURCE_REQUEST_ID = FCC_CUST_DIM.V_ALT_CUST_ID AND V_TARGET_KEY = FCC_CS_MATCHED_RESULT_BULK.V_TARGET_KEY AND V_TARGET_INDEXNAME = FCC_CS_MATCHED_RESULT_BULK.V_TARGET_INDEXNAME )

Why is my query inserting the same values when I have added a 'not exists' parameter that should avoid this from happening?

My query should stop inserting values, as the not exists statement is satisfied (I have checked both tables) and matching incidents exist in both tables, any ideas why values are still being returned?
Here is the code:
INSERT INTO
odwh_system.ead_incident_credit_control_s
(
incident
)
SELECT DISTINCT
tp.incident
FROM
odwh_data.ead_incident_status_audit_s ei
INNER JOIN odwh_data.ead_incident_s tp ON ei.incident=tp.incident
WHERE
ei.status = 6
OR
ei.status = 7
AND NOT EXISTS
(
SELECT
true
FROM
odwh_system.ead_incident_credit_control_s ead
WHERE
ead.incident = tp.incident
)
AND EXISTS
(
SELECT
true
FROM
odwh_work.ead_incident_tp_s tp
WHERE
tp.incident = ei.incident
);
dont reuse table aliases
use sane aliases
avoid AND/OR conflicts; prefer IN()
INSERT INTO odwh_system.ead_incident_credit_control_s (incident)
SELECT -- DISTINCT
tp.incident
FROM odwh_data.ead_incident_s dtp
WHERE NOT EXISTS (
SELECT *
FROM odwh_system.ead_incident_credit_control_s sic
WHERE sic.incident = dtp.incident
)
AND EXISTS (
SELECT *
FROM odwh_work.ead_incident_tp_s wtp
JOIN odwh_data.ead_incident_status_audit_s dis ON wtp.incident = dis.incident AND dis.status IN (6 ,7)
WHERE wtp.incident = dtp.incident
);

with, works in the first query, but not in the second

i have this FUNCTION, that check if there are results in the first consult, table_one
if not are results, check in the second_table
separate each query works, but if join it, just work the first sentence but not the second one
CREATE OR REPLACE FUNCTION get_data(id INT)
RETURNS TABLE(
id INT,
created_at TIMESTAMP,
attempts INT,
status VARCHAR
)
language plpgsql
AS
$$
DECLARE
_SENT VARCHAR := 'SENT';
BEGIN
RETURN QUERY
WITH r AS (
SELECT p_i.id, a_r.created_at, a_r.attempts,
CASE a_r.status
WHEN 'PENDING' THEN _SENT
END AS status
FROM table_one p_i
LEFT JOIN (
SELECT a_r.table_one_id, max(a_r.id) id
FROM awa_req a_r
GROUP BY a_r.table_one_id
) last_md on last_md.table_one_id = p_i.id
LEFT JOIN awa_req a_r on a_r.table_one_id = last_md.table_one_id and a_r.id = last_md.id
WHERE p_i.user_id = $1
AND p_i.deleted_at IS NULL
)
SELECT * FROM r
UNION ALL
SELECT p_i.id, m_d.created_at, m_d.attempts,
CASE
WHEN m_d.confirmed_at IS NULL THEN _SENT
END AS status
FROM pay_ins p_i
LEFT JOIN (
SELECT max(t.id) AS id, t.pay_ins_id
FROM table_two t
GROUP BY t.pay_ins_id
) last_md on last_md.pay_ins_id = p_i.id
LEFT JOIN table_two m_d on m_d.pay_ins_id = last_md.pay_ins_id and m_d.id = last_md.id
AND NOT EXISTS (
SELECT * FROM r
);
END;
$$;
best
This part will eliminate all rows from the UNION clause if any rows exist in r:
AND NOT EXISTS (
SELECT * FROM r
);
It should instead be something like:
AND NOT EXISTS (
SELECT FROM r WHERE r.id = p_i.id
)

How to UPDATE pivoted table in SQL SERVER

I have flat table which I have to join using EAN attribute with my main table and update gid (id of my main table).
id attrib value gid
1 weight 10 NULL
1 ean 123123123112 NULL
1 color blue NULL
2 weight 5 NULL
2 ean 331231313123 NULL
I was trying to pivot ean rows into column, next join on ean both tables, and for this moment everything works great.
--update SideTable
--set gid = ab_id
select gid, ab_id
from SideTable
pivot (max (value) for attrib in ([EAN],[MPN])) as b
join MainTable as c
on c.ab_ean = b.EAN
where b.EAN !='' AND c.ab_archive = '0'
When I am selecting both id columns is okey, but when I am uncomment first lines and delete select whole table is set with first gid from my main table.
It have to set my main id into all attributes where ID where ean is matched from my main table.
I am sorry for my terrible english but I hope someone can help me, with that.
The reason your update does not work is that you don't have any link between your source and target for the update, although you reference sidetable in the FROM clause, this is effectively destroyed by the PIVOT function, leaving no link back to the instance of SideTable that you are updating. Since there is no link, all rows are updated with the same value, this will be the last value encountered in the FROM.
This can be demonstrated by running the following:
DECLARE #S TABLE (ID INT, Attrib VARCHAR(50), Value VARCHAR(50), gid INT);
INSERT #S
VALUES
(1, 'weight', '10', NULL), (1, 'ean', '123123123112', NULL), (1, 'color', 'blue', NULL),
(2, 'weight', '5', NULL), (2, 'ean', '331231313123', NULL);
SELECT s.*
FROM #S AS s
PIVOT (MAX(Value) FOR attrib IN ([EAN],[MPN])) AS pvt;
You clearly have a table aliased s in the FROM clause, however because you have used pivot you cannot use SELECT s*, you get the following error:
The column prefix 's' does not match with a table name or alias name used in the query.
You haven't provided sample data for your main table, but I am about 95% certain your PIVOT is not needed, I think you can get your update using just normal JOINs:
UPDATE s
SET gid = ab_id
FROM SideTable AS s
INNER JOIN SideTable AS ean
ON ean.ID = s.ID
AND ean.attrib = 'ean'
INNER JOIN MainTable AS m
ON m.ab_EAN = ean.Value
WHERE m.ab_archive = '0'
AND m.ab_EAN != '';
As per comment to the question, you need to use update + select statement.
A standard version looks like:
UPDATE
T
SET
T.col1 = OT.col1,
T.col2 = OT.col2
FROM
Some_Table T
INNER JOIN
Other_Table OT
ON
T.id = OT.id
WHERE
T.col3 = 'cool'
As to your needs:
update a
set a.gid = p.ab_id
from SideTable As a
Inner join (
select gid, ab_id
from SideTable
pivot (max (value) for attrib in ([EAN],[MPN])) as b
join MainTable as c
on c.ab_ean = b.EAN
where b.EAN !='' AND c.ab_archive = '0') p ON a.ean = p.EAN
try and break it down a bit more like this..
update SideTable
set SideTable.gid = p.ab_id
FROM
(
select gid, ab_id
from SideTable
pivot (max (value) for attrib in ([EAN],[MPN])) as b
join MainTable as c
on c.ab_ean = b.EAN
where b.EAN !='' AND c.ab_archive = '0'
) p
WHERE p.EAN = SideTable.EAN

Adding the results of multiple SQL selects?

I have three SQL selects, the results of which I need to add together. Two of the three use fairly complex joins.
select sum(field_one) from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=:id
select sum(field_two) from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=:id
select sum(field_three) from t_e where t_e.user_id=:id
What I need is the sum of all three values. sum(field_one)+sum(field_two)+sum(field_three). Is there anyway to do this in a single statement?
You could UNION ALL them.
Do not use UNION, since it omits duplicate values (5+5+5 would result in 5).
Select Sum(s)
From
(
Select Sum(field_one) As s ...
Union All
Select Sum(field_two) ...
Union All
Select Sum(field_three) ...
) x
You can do this without using Union like this
Sample Query
select( (select 15) + (select 10) + (select 20))
Your Query
select
(
(select sum(field_one) from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=:id) +
(select sum(field_two) from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=:id) +
(select sum(field_three) from t_e where t_e.user_id=:id)
)
You can use a UNION and a subselect to do that:
select sum(`sum`) FROM
(
select sum(field_one) as `sum` from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=:id
UNION ALL
select sum(field_two) from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=:id
UNION ALL
select sum(field_three) from t_e where t_e.user_id=:id
) as x;
Edit: Updated my answer to use UNION ALL, as suggested by Peter Lang.