Syntax error in Merge statement SQL - merge

I have two other questions about this but this one is more focused. The Merge statement's basic structure is given below. In the interest of time and length, I have summarized some of the details Originally, I was going to try to merge 8 into 1. That has been a fruitless venture so I have narrowed it down. For this one, I am trying to combine industry21 and industry4 knowing that there are 8 rows of primary key duplication. The primary key is a compound one comprised of 9 fields (not sure if that is relevant). They are 13 foreign keys.
From looking at the code below, can someone see why I would get an incorrect syntax on the = sign on the first bold item. Next on the same bold line, why when I hover over the . between source and periodtype on the same line do I get an error about "Merge Statement must be terminated in a column"
Merge industry4 AS TARGET
USING industry21 as SOURCE
ON (target.primarykey1 = Source.primarykey1) or (target.primarykey2 =
Source.primarykey2) or..... (target.primarykey9 = Source.primarykey9)
--When records are matched, update
--the records if there is any change
WHEN MATCHED AND
TARGET.foreignkey1 <> SOURCE.foreignkey1
OR .... TARGET.foreignkey13 <> SOURCE.foreignkey2
THEN
UPDATE SET TARGET.pk1 = SOURCE.pk1,
TARGET.pk2 = SOURCE.pk2
**TARGET.periodtype(pk5) = SOURCE.periodtype (pk5)**
.....
TARGET.fk13 = SOURCE.fk13
--When no records are matched, insert
--the incoming records from source
--table to target table
WHEN NOT MATCHED BY TARGET THEN
INSERT (fieids 1-22)
VALUES (SOURCE.pk1, SOURCE.pk2......SOURCE.fk13)
WHEN NOT MATCHED BY SOURCE THEN
DELETE

I was able to accomplish the task using the following code. It is not related to my original question but apparently merge statements are not the best nor popular way to do this.
SELECT x.*
INTO [NEW_TABLE]
FROM (SELECT * FROM TABLE1
UNION
SELECT * FROM TABLE2) x

Related

How to update multiple rows using a sub-query and order by in the sub-query?

I am trying to update a table using a sub-query, however the sub-query contains multiple joins as I am getting data from multiple tables, and as a business requirement I am forced to add an Order by in the sub-query to sort elements based on the primary key, if order by is not added then the output is not accurate. A simple example without the joins of what I am trying to do is:
UPDATE EMPLOYEES e
SET (e.JOB, e.SAL, e.COMM) =
(
SELECT p.JOB, p.SAL, p.COMM FROM EMP p WHERE p.ENAME = e.ENAME ORDER BY p.DEPTNO
)
WHERE DEPTNO = 30;
The main issue is not being able to use Order by in sub-query.
This throws an error message:
Error at line 4/80: ORA-00907: missing right parenthesis
ORA-06512: at "SYS.WWV_DBMS_SQL_APEX_220100", line 847
ORA-06512: at "SYS.DBMS_SYS_SQL", line 1658
ORA-06512: at "SYS.WWV_DBMS_SQL_APEX_220100", line 833
ORA-06512: at "APEX_220100.WWV_FLOW_DYNAMIC_EXEC", line 1903
If I remove the Order by from the sub-query then I get no error message, however my result is not the expected. How can I achieve this?
It is syntactically invalid to have an ORDER BY clause in the outer-most sub-query of a correlated sub-query as the order of the results does not matter as there should only be a single matching row for the sub-query. Therefore the general answer to your question is that it is impossible to have an ORDER BY clause because the syntax forbids it.
Since Oracle 12, there is an exception which allows an ORDER BY clause in a correlated sub-query and that is when you also use FETCH FIRST ROW ONLY to guarantee that the sub-query returns only a single row.
So, if you are getting multiple rows for the sub-query and you only want the first row then, from Oracle 12, you can use:
UPDATE EMPLOYEES e
SET (e.JOB, e.SAL, e.COMM) = (SELECT p.JOB, p.SAL, p.COMM
FROM EMP p
WHERE p.ENAME = e.ENAME
ORDER BY p.DEPTNO
FETCH FIRST ROW ONLY)
WHERE DEPTNO = 30;
However, it seems more likely that you would want to use something else to correlate the queries so that you only ever get a single row.
as a business requirement I am forced to add an Order by in the sub-query to sort elements based on the primary key
This does not appear to be what you are doing as you are sorting by the department number, DEPTNO, and it seems to be unlikely that the primary key for an employee is the number of their department.
db<>fiddle here

Make MERGE statement in BODS

I have SAP BODS as ETL tool running towards Oracle Exadata. I would like to produce a merge into statement from BODS that include a where clause, limiting the columns that will be updated when found a match.
The merge statement I have today looks like this:
MERGE INTO TargetTable s
USING
(SELECT columns
FROM "sourceTable"
) n
ON ((s.Column= n.Column) WHEN MATCHED THEN
UPDATE SET s."Column" = n.Column
-----MISSING where clause ------
WHEN NOT MATCHED THEN
INSERT /*+ APPEND */ (s.columns)
VALUES (n.Columns);
Use DS target Auto Correct load. There are several options to play with there and if you
allow merge sets to 'Yes'
You will have the above query generated. But please take care as proper keys should be set in target for this to happen.
Cheerz.
Shaz

are INTO, FROM an JOIN the only ways to get a table?

I'm currently writing a script which will allow me to input a file (generally .sql) and it'll generate a list of every table that's used in that file. the process is simple as it opened the input file, checks for a substring and if that substring exists outputs the line to the screen.
the substring that being checked is tsql keywords that is indicative of a selected table such as INTO, FROM and JOIN. not being a T-SQL wizard those 3 keywords are the only ones i know of that are used to select a table in a query.
So my question is, in T-SQL are INTO, FROM an JOIN the only ways to get a table? or are these others?
There're many ways to get a table, here're some of them:
DELETE
FROM
INTO
JOIN
MERGE
OBJECT_ID (N'dbo.mytable', N'U') where U is the object type for table.
TABLE, e.g. ALTER TABLE, TRUNCATE TABLE, DROP TABLE
UPDATE
However, by using your script, you'll not only get real tables, but maybe VIEW and temporary table. Here're 2 examples:
-- Example 1
SELECT *
FROM dbo.myview
-- Example 2
WITH tmptable AS
(
SELECT *
FROM mytable
)
SELECT *
FROM tmptable

Merge SQL to Exclude Duplicate Records So Merge 2nd time Doesn't Fail

I have three tables and only one that I directly control and am doing a MERGE between them. See my abbreviated but working example here (sqlfiddle example).
I am doing a MERGE between table 1 and Table 2 to Table 3. Table 1 has duplicate data which the MERGE (erroneously) can handle on the first run (insert) but fails with this message on the second run (update).
The MERGE statement attempted to UPDATE or DELETE the same row more
than once.
My question is, can the MERGE be written to either use an EXCEPT such as
SELECT AdFull FROM [dbo].[Users] WHERE AdFull IS NOT NULL
EXCEPT
SELECT AdFull FROM [dbo].[Users]
WHERE AdFull IS NOT NULL
GROUP BY AdFull
HAVING COUNT(*) = 1
or a different Join to only show users that are not duplicated? Or even a way to select a specific one of the duplicates?
Answered Questions
MERGE is a working Insert due to the nature of Fiddle. But due (AFAIK) to the stateless nature of fiddle one never sees the error in Fiddle on a second run, because a merge never happens with the data, only inserts.
Ignore Rows: Actually I would eventually like to use an individual duplicate row via divining of one based on a condition. The actual data table I am dealing with away from the fiddle example has more columns and it would be nice to maybe select a specific row in a duplicate set due to a specific condition.
The example doesn't bare it out, but yes the duplicates are due to the computed AdFull column. Think of a system adding a temp employee, that user gets a row. Then the temp employee gets hired on as fulltime, keeps the ad account but then gets another row in the user table. Yes I know it shouldn't happen. So that is how a duplicate comes about.
(Duplicate values Table 3) Table three is a result table that can be cleaned out for any duplicates to start this process afresh.
In your MERGE statement can you do something similar this?
MERGE INTO [dbo].Table3 AS T3
USING
(
SELECT
AdFull,
MAX(StartedOn)
FROM [dbo].Table2 AS [ad]
GROUP BY AdFull
) AS T2
ON (T2.AdFull = T3.AdFull)
WHEN MATCHED THEN UPDATE blah
WHEN NOT MATCHED THEN INSERT blah
Using the MAX aggregate with a GROUP BY should give you only the information from when the temp was hired on. Then if the AdFull matches you can simply UPDATE Table3 with the most recent information and if there is no match then INSERT a new row.
UPDATE: If I fail to mention that MERGE should be used with caution I will take flak from #AaronBertrand.

The MERGE statement attempted to UPDATE or DELETE the same row more than once

I have a source table with three fields
Declare #tmptvp table
(
ID int,
StartDate Datetime,
EndDate Datetime
)
Insert #tmptvp values(1,'2013-04-28','2013-04-30')
Insert #tmptvp values(2,'2013-05-01','2013-06-30')
select * from #tmptvp
My target table is 'InsertDate' contains the following data.
Insert InsertDate values(1,'2013-04-28','2013-06-30')
while merging
MERGE (#tmptvp) as TGT
USING
(select ID,StartDate,EndDate FROM #tmptvp) AS SRC
ON
(TGT.StartDate = SRC.StartDate OR TGT.EndDate = SRC.EndDate)
WHEN MATCHED THEN
UPDATE SET TGT.StartDate = CASE WHEN SRC.StartDate < TGT.StartDate THEN SRC.StartDate ELSE TGT.StartDate END,
TGT.EndDate = CASE WHEN SRC.EndDate > TGT.EndDate THEN SRC.EndDate ELSE TGT.EndDate END,
WHEN NOT MATCHED THEN
INSERT (ID,StartDate,EndDate)
VALUES
(SRC.ID,SRC.StartDate,SRC.EndDate);
Above merge statement throws
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.
please check this site
http://www.sqlsafety.com/?p=665
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.” several times and am always forced to run back through the query logic to see what has occurred. Reading the message it is fairly self explanatory as to what has happened. A row in the target table will be affected more than once from within the MERGE statement which causes the query to fail.
Best regards