SQL: Error when using MERGE - sql

I'm trying to update or insert one table based on the entries present in another table. But when I try to use MERGE to accomplish this. I'm getting below error message.
Error: The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Do I have to include more conditions in ON clause?
Code:
IF EXISTS (SELECT ShoppingCartNo FROM tbPOValidation WHERE ShoppingCartNo <> '')
BEGIN
MERGE tbPOValidation AS t
USING tbPOValidationTemp AS s
ON (CONVERT(VARCHAR(30),t.ShoppingCartNo)+CONVERT(VARCHAR(30),t.lineitemNo)+CONVERT(VARCHAR(30),t.PONo)) =
(CONVERT(VARCHAR(30),s.ShoppingCartNo)+CONVERT(VARCHAR(30),s.lineitemNo)+CONVERT(VARCHAR(30),s.PONo))
--When records are matched, update
--the records if there is any change
WHEN MATCHED AND (CONVERT(VARCHAR(30),t.ShoppingCartNo)+CONVERT(VARCHAR(30),t.lineitemNo)+CONVERT(VARCHAR(30),t.PONo)) =
(CONVERT(VARCHAR(30),s.ShoppingCartNo)+CONVERT(VARCHAR(30),s.lineitemNo)+CONVERT(VARCHAR(30),s.PONo))
THEN
UPDATE SET t.SupplierName = s.SupplierName, t.DUNS = s.DUNS, t.PONo = s.PONo, t.LineItemNo = s.LineItemNo, t.PurchDocItemDesc = s.PurchDocItemDesc,
t.POIssueDate = s.POIssueDate, t.DeliveryDate = s.DeliveryDate, t.PurchDocType = s.PurchDocType, t.MtrNo = s.MtrNo, t.Location = s.Location,
t.PayTerms = s.PayTerms, t.BlanketNo = s.BlanketNo, t.BlanketLineItemNo = s.BlanketLineItemNo, t.ShoppingCartNo = s.ShoppingCartNo,
t.SHCItmNo = s.SHCItmNo, t.ItemPricing = s.ItemPricing, t.ItmPrcCurrency = s.ItmPrcCurrency, t.Per = s.Per, t.POValue = s.POValue,
t.POValueCurrency = s.POValueCurrency, t.Qty = s.Qty, t.UOM = s.UOM, t.MFGName = s.MFGName, t.MFGPartNO = s.MFGPartNO, t.Description = s.Description,
t.Remarks = s.Remarks, t.Accept = s.Accept, t.AcceptedBy = s.Duns, t.AcceptedOn = GETDATE(), t.RejectionReason = s.RejectionReason
--When no records are matched, insert
--the incoming records from s
--table to t table
WHEN NOT MATCHED BY TARGET THEN
INSERT (SupplierName, DUNS, PONo, LineItemNo, PurchDocItemDesc, POIssueDate, DeliveryDate, PurchDocType, MtrNo,
Location, PayTerms, BlanketNo, BlanketLineItemNo, ShoppingCartNo, SHCItmNo, ItemPricing, ItmPrcCurrency, Per, POValue, POValueCurrency,
Qty, UOM, MFGName, MFGPartNO, Description, Remarks, Accept, AcceptedBy, AcceptedOn, RejectionReason)
VALUES (s.SupplierName, s.DUNS, s.PONo, s.LineItemNo, s.PurchDocItemDesc, s.POIssueDate, s.DeliveryDate, s.PurchDocType, s.MtrNo,
s.Location, s.PayTerms, s.BlanketNo, s.BlanketLineItemNo, s.ShoppingCartNo, s.SHCItmNo, s.ItemPricing, s.ItmPrcCurrency, s.Per, s.POValue,
s.POValueCurrency,s.Qty, s.UOM, s.MFGName, s.MFGPartNO, s.Description, s.Remarks, s.Accept, s.AcceptedBy, s.AcceptedOn, s.RejectionReason);
END

It is likely that the concatenation of fields is not unique i.e 10 11 12 would be equal to 101 11 2. Put special characters between the fields:
ON (CONVERT(VARCHAR(30),t.ShoppingCartNo)+'~' +CONVERT(VARCHAR(30),t.lineitemNo)+'~'+CONVERT(VARCHAR(30),t.PONo)) =
(CONVERT(VARCHAR(30),s.ShoppingCartNo)+'~' +CONVERT(VARCHAR(30),s.lineitemNo)+'~' +CONVERT(VARCHAR(30),s.PONo))

Related

insert into select oracle

i need insert rows on a table that comes of other, the colums in the table are empty but in te base table are full, im using a insert into select but i get: 'Error SQL: ORA-00926'
INSERT INTO TABLEROS.V_GRR_EEAF (PER_ID, EDAD, F_NACIMIENTO, CICLO_VITAL, GENERO_HOM, PERT_ETNICA, DISCAP
)A
(SELECT PER_ID, EDAD, F_NACIMIENTO, CICLO_VITAL, GENERO_HOM, PERT_ETNICA, DISCAP
FROM FUENTES.V_GRR_EEAF#CONSULTAFUENTES80 B
WHERE A.ID_BASE = B.ID_BASE
);
If I understand, you want to update empty columns in A where id_base exists in B and the updated values should be same as columns in B.
use this statement, it works:
MERGE INTO TABLEROS.V_GRR_EEAF a
USING FUENTES.V_GRR_EEAF#CONSULTAFUENTES80 b
ON(a.ID_BASE = b.ID_BASE)
WHEN MATCHED THEN
UPDATE SET
a.PER_ID = b.PER_ID,
a.EDAD = b.EDAD,
a.F_NACIMIENTO = b.F_NACIMIENTO,
a.CICLO_VITAL = b.CICLO_VITAL,
a.GENERO_HOM = b.GENERO_HOM,
a.PERT_ETNICA = b.PERT_ETNICA,
a.DISCAP = b.DISCAP;
commit;

How to Update to SET Table1.ColumnX = Table2.ColumnX with a where clause

Let's say I have one table called InsuranceMember which contains all members of insurance plans and their spouses. But oh no! for spouses that have a CountryCD of 'Canada' and have a PlanCD of '99999', the MemberNum's (primary key) are all incorrect in this table!
But thankfully, there is a table called InsurancePlan, that contains spouses, and where these Spouses's MemberNum's (also primary key) are all correct!
So in this hypothetical I need a conditional update statement that sets InsuranceMember.MemberNum = InsurancePlan.MemberNum where CountryCD = 'Canada' and PlanCD = '99999'
How can I write a query to make this work and update each row.
When I've tried writing this query I always get back this error:
-811
THE RESULT OF AN EMBEDDED SELECT STATEMENT OR A SUBSELECT IN THE SET CLAUSE OF AN UPDATE STATEMENT IS A TABLE OF MORE THAN ONE ROW, OR THE RESULT OF A SUBQUERY OF A BASIC PREDICATE IS MORE THAN ONE VALUE
This is very confusing for me as a beginner in SQL, but I'm sure the situation I'm describing is something many have dealt with.
Edit: Here is an example of code I use that produces that update:
UPDATE PRD.InsuranceMember mem
set mem.MemberNum = ( Select pln.MemberNum
from PRD.InsurancePlan pln
where mem.MemberNum <> pln.MemberNum
and mem.MoneySource = pln.MoneySource
)
WHERE mem.MemberNum = (SELECT pln2.MemberNum FROM PRD.InsurancePlan pln2
WHERE mem.ClientCd = pln2.ClientCd
AND mem.PLanCd = pln2.PlanCd)
AND Mem.MoneySource='3'
AND Mem.CountryCd = 'Canada'
AND Mem.PlanCd = '99999'
;
Try adding a FETCH FIRST ROW ONLY to the end of each of your subqueries, which will inform the database that those expressions will not return multiple values.
UPDATE PRD.InsuranceMember mem
SET mem.MemberNum = ( SELECT pln.MemberNum
FROM PRD.InsurancePlan pln
WHERE mem.MemberNum <> pln.MemberNum
AND mem.MoneySource = pln.MoneySource
FETCH FIRST ROW ONLY
)
WHERE mem.MemberNum = (SELECT pln2.MemberNum
FROM PRD.InsurancePlan pln2
WHERE mem.ClientCd = pln2.ClientCd
AND mem.PLanCd = pln2.PlanCd
FETCH FIRST ROW ONLY
)
AND mem.MoneySource='3'
AND mem.CountryCd = 'Canada'
AND mem.PlanCd = '99999'
;
Using an UPDATE of a SELECT can help in this situation as you can run just the SELECT part and ensure that the newMemberNum sub-select only returns one row
UPDATE (
SELECT
MemberNum
, MoneySource
, CountryCd
, PlanCd
, ( Select pln.MemberNum
from PRD.InsurancePlan pln
where mem.MemberNum <> pln.MemberNum
and mem.MoneySource = pln.MoneySource
) AS NewMemberNum
FROM
PRD.InsuranceMember mem
)
SET MemberNum = NewMemberNum
WHERE
MoneySource='3'
AND CountryCd = 'Canada'
AND PlanCd = '99999'
AND MemberNum IS DISTINCT FROM NewMemberNum
So you might need a MAX(pln.MemberNum) or DISTINCT some such in the sub-select to ensure that at most one row is found for each selected row in PRD.InsuranceMember

My UPDATE statement with WHERE EXISTS does not limit to the SELECT statement results

I have data in a temporary table and I am checking for duplicates in two other tables. I want to set a flag on the temp table (SET DupFlag = TRUE) for all duplicates found. My SELECT statement works perfectly, returning only the 48 duplicates that I entered to test with. But when I add UPDATE and WHERE EXISTS, every record in idTempImport2 is set to TRUE instead of just the 48 records returned from the SELECT statement. Is my syntax wrong? It looks like this:
UPDATE idTempImport2 as tmp2 SET DupFlag = TRUE
WHERE EXISTS
(SELECT * FROM idTempImport2 tmp2
LEFT JOIN (SELECT im.idDate, im.UserID, im.ActionID, im.IsHC, idn.Epic1, idn.Epic2
FROM idMain AS im
INNER JOIN idNotes AS idn ON im.aID = idn.MainID
WHERE idDate BETWEEN "2017-01-02" AND "2017-01-31") AS qry
ON qry.idDate = tmp2.idDate AND qry.UserID = tmp2.UserID AND qry.ActionID = tmp2.ActionID AND qry.Epic1 = clng(tmp2.Epic1) AND qry.Epic2 = clng(tmp2.Epic2)
WHERE qry.Epic1 <> NULL);
I think the ultimate issue is that you want a correlated subquery. As written, the subquery has no connection to the outer query, so it is likely that at least one row meets the condition. So, everything gets updated.
I think you intend:
UPDATE idTempImport2 as tmp2
SET DupFlag = TRUE
WHERE EXISTS (SELECT im.idDate, im.UserID, im.ActionID, im.IsHC, idn.Epic1, idn.Epic2
FROM idMain AS im INNER JOIN
idNotes AS idn
ON im.aID = idn.MainID
WHERE idDate BETWEEN "2017-01-02" AND "2017-01-31" AND
im.idDate = tmp2.idDate AND im.UserID = tmp2.UserID AND
im.ActionID = tmp2.ActionID AND
?.Epic1 = clng(tmp2.Epic1) AND ?.Epic2 = clng(tmp2.Epic2)
);

Merge Source Table Into Target Table using subjoins

I am new to SQLDeveloper. Please help me in correcting the merge syntax.I want to merge the data from act_sl tavle into act_sls_0 table
I am using 2 joins in From Clause.
But I am Getting Errors :
Error(13,13): PL/SQL: ORA-00969: missing ON keyword
Error(4,1): PL/SQL: SQL Statement ignored
merge into act_sls_0 using(
( select * from
(select a_0.asp, gadim.uic as ga, pmm_styleid, week, colorcode , sizecode, storenum, units_asly,retail_asly,
cost_asly ,units_asregly,retail_asregly,units_asmkdly,retail_asmkdly,units_as_pln,retail_as_pln
from act_sls
join dimension w on w.externalkey = 'W'||substr(WEEK,3,2)||'_'||substr(WEEK,5,2)
join a_0 on ( w.externalkey between startweek and endweek)
join dimension strdim on strdim.externalkey = (case when length(storenum) <= 4 then RPAD('STR-', 8 - length(storenum), '0') else 'STR-' END) || storenum
join store_info_0 str on store = strdim.uic
join dimension gadim on gadim.externalkey = decode(store_type, 'RETAIL', 'GA-01', 'ECOM', 'GA-02', '')
where trendweeks < 6)t1
join(select distinct asp, product, ga, color, sstyl_shade, pmm_styleid from aplc_1 aplc
join apc_1 apc using (asp,product,color)
where activeitem = 1 and ga!=0 and color != 0)t2
on (t1.asp = t2.asp and
t1.pmm_styleid = t2.pmm_styleid
and (case when length(t1.colorcode) <= 4 then RPAD('SHD-', 8 - length(t1.colorcode), '0') else 'SHD-' END) || t1.colorcode = t2.sstyl_shade
and t1.ga = t2.ga))src
on (trg.asp = src.asp and trg.pmm_styleid = src.pmm_styleid and trg.colorcode = src.colorcode and trg.ga = src.ga)
when matched THEN
update SET
when matched THEN
update SET
trg.UNITS_ASLY = src.UNITS_ASLY,
trg.RETAIL_ASLY = src.RETAIL_ASLY,
trg.COST_ASLY = src.COST_ASLY,
trg.UNITS_ASREGLY = src.UNITS_ASREGLY,
trg.RETAIL_ASREGLY = src.RETAIL_ASREGLY,
trg.UNITS_ASMKDLY = src.UNITS_ASMKDLY,
trg.RETAIL_ASMKDLY = src.RETAIL_ASMKDLY,
trg.UNITS_AS_PLN = src.UNITS_AS_PLN,
trg.RETAIL_AS_PLN = src.RETAIL_AS_PLN
when not matched then insert
(trg.asp,trg.ga, trg.pmm_styleid, trg.colorcode,trg.sizecode,trg.storenum,trg.week,trg.UNITS_ASLY,trg.RETAIL_ASLY ,trg.COST_ASLY , trg.UNITS_ASREGLY ,trg.RETAIL_ASREGLY ,
trg.UNITS_ASMKDLY ,trg.RETAIL_ASMKDLY ,trg.UNITS_AS_PLN ,trg.RETAIL_AS_PLN )
values
(src.asp,src.ga, src.pmm_styleid, src.colorcode,src.sizecode,src.storenum,src.week,src.UNITS_ASLY,src.RETAIL_ASLY,src.COST_ASLY,src.UNITS_ASREGLY,
src.RETAIL_ASREGLY, src.UNITS_ASMKDLY, src.RETAIL_ASMKDLY, src.UNITS_AS_PLN, src.RETAIL_AS_PLN);
The format for a merge statement is:
merge into <target_table> tgt
using <table_name or subquery> src
on (<join conditions between the target and source datasets>)
when matched then
update set ...
when not matched then
insert (...)
values (...);
Quite apart from the fact that your source subquery is incorrect (there are errors around where the t1 and t2 are; too many brackets, inappropriately trying to alias something etc), whilst you have join conditions inside your subquery, you're completely missing the ON clause for the merge itself.
You need to define the join conditions that match the data returned by your source subquery to your target table.
Now the error is : src.ga - Invalid Identifier
Although I have ga table in Trg table and src table .
merge into act_sls_0 trg using( select * from
(select a_0.asp, gadim.uic as ga, pmm_styleid, week, colorcode , sizecode, storenum, units_asly,retail_asly,
cost_asly ,units_asregly,retail_asregly,units_asmkdly,retail_asmkdly,units_as_pln,retail_as_pln
from act_sls
join dimension w on w.externalkey = 'W'||substr(WEEK,3,2)||'_'||substr(WEEK,5,2)
join a_0 on ( w.externalkey between startweek and endweek)
join dimension strdim on strdim.externalkey = (case when length(storenum) <= 4 then RPAD('STR-', 8 - length(storenum), '0') else 'STR-' END) || storenum
join store_info_0 str on store = strdim.uic
join dimension gadim on gadim.externalkey = decode(store_type, 'RETAIL', 'GA-01', 'ECOM', 'GA-02', '')
where trendweeks < 6)t1
join(select distinct asp, product, ga, color, sstyl_shade, pmm_styleid from aplc_1 aplc
join apc_1 apc using (asp,product,color)
where activeitem = 1 and ga!=0 and color != 0)t2
on (t1.asp = t2.asp and
t1.pmm_styleid = t2.pmm_styleid
and (case when length(t1.colorcode) <= 4 then RPAD('SHD-', 8 - length(t1.colorcode), '0') else 'SHD-' END) || t1.colorcode = t2.sstyl_shade
and t1.ga = t2.ga))src
on (trg.asp = src.asp and trg.pmm_styleid = src.pmm_styleid and trg.colorcode = src.colorcode and trg.ga = src.ga)
when matched THEN
update SET
trg.UNITS_ASLY = src.UNITS_ASLY,
trg.RETAIL_ASLY = src.RETAIL_ASLY,
trg.COST_ASLY = src.COST_ASLY,
trg.UNITS_ASREGLY = src.UNITS_ASREGLY,
trg.RETAIL_ASREGLY = src.RETAIL_ASREGLY,
trg.UNITS_ASMKDLY = src.UNITS_ASMKDLY,
trg.RETAIL_ASMKDLY = src.RETAIL_ASMKDLY,
trg.UNITS_AS_PLN = src.UNITS_AS_PLN,
trg.RETAIL_AS_PLN = src.RETAIL_AS_PLN
when not matched then insert
(trg.asp,trg.ga, trg.pmm_styleid, trg.colorcode,trg.sizecode,trg.storenum,trg.week,trg.UNITS_ASLY,trg.RETAIL_ASLY ,trg.COST_ASLY ,trg.UNITS_ASREGLY ,trg.RETAIL_ASREGLY ,
trg.UNITS_ASMKDLY ,trg.RETAIL_ASMKDLY ,trg.UNITS_AS_PLN ,trg.RETAIL_AS_PLN )
values
(src.asp,src.ga, src.pmm_styleid, src.colorcode,src.sizecode,src.storenum,src.week,src.UNITS_ASLY,src.RETAIL_ASLY,src.COST_ASLY,src.UNITS_ASREGLY,
src.RETAIL_ASREGLY, src.UNITS_ASMKDLY, src.RETAIL_ASMKDLY, src.UNITS_AS_PLN, src.RETAIL_AS_PLN);
commit;

SQL Load Fact with Merge Statement Slow

I'm loading a fact table using MERGE and it's taking 44 minutes for 1 million records. Is there a way I can improve this?
My query:
MERGE INTO dbo.FactProjMarketCode AS target
USING (
SELECT
SourceSystem = 'ORACLE_ERP',
ProjMarketCodeSourceId = jmc.XT_JOB_MARKETING_CODE_ID,
p.ProjectId,
MarketCodeId = ISNULL(mc.MarketingCodeId,-1),
Weight = 0.01 * ISNULL(jmc.WEIGHT,100),
WasMissing = CASE WHEN jmc.WEIGHT IS NULL THEN 1 ELSE 0 END,
jmc.LAST_UPDATE_DATE
FROM
dimProject p
LEFT JOIN stage.XT_JOB_MARKETING_CODE jmc
ON p.ProjectSourceId = jmc.XT_PROJECT_ID
LEFT JOIN DimMarketingCode mc
ON jmc.MARKETING_CODE = mc.MarketingCode -- should create column MarketingCodeSourceId
AND mc.SourceSystem = 'ORACLE_ERP'
WHERE
p.SourceSystem = 'ORACLE_ERP'
) AS source
ON target.SourceSystem = source.SourceSystem
AND target.ProjMarketCodeSourceId = source.ProjMarketCodeSourceId
WHEN MATCHED AND source.LAST_UPDATE_DATE > target.LAST_UPDATE_DATE
THEN UPDATE SET
target.ProjectId = source.ProjectId,
target.MarketCodeId = source.MarketCodeId,
target.Weight = source.WEIGHT,
target.WasMissing = source.WasMissing,
target.LAST_UPDATE_DATE = source.LAST_UPDATE_DATE
WHEN NOT MATCHED BY target
THEN INSERT (
SourceSystem,
ProjMarketCodeSourceId,
ProjectId,
MarketCodeId,
Weight,
WasMissing,
LAST_UPDATE_DATE
) VALUES (
source.SourceSystem,
source.ProjMarketCodeSourceId,
source.ProjectId,
source.MarketCodeId,
source.Weight,
source.WasMissing,
source.LAST_UPDATE_DATE
)
WHEN NOT MATCHED BY source
THEN DELETE;