Merge with only 'when matched then update' In Oracle 9i - sql

I am working at a company with Oracle 9i 9.2, and I am unable to upgrade.
A merge which only does an update on matched, not an insert on not-matched, seems not to work in this version.
I am trying to do:
MERGE INTO CDLREFWORK.pricing d --table to insert to
USING V_REC S --table source
ON ( D.item_id = S.item_id
and d.line_type = s.line_type
AND d.price_code =s.price_code )
WHEN MATCHED THEN UPDATE SET
d.APPLICATION_ID='CPMASI',
d.SYS_UPDATE_DATE=SYSDATE,
d.OPERATOR_ID=nvl(s.OPERATOR_ID, d.OPERATOR_ID),
d.LOCATION_ID=nvl(s.LOCATION_ID,d.LOCATION_ID),
d.ITEM_ID= nvl(s.ITEM_ID,d.ITEM_ID),
d.LINE_TYPE= nvl(s. LINE_TYPE, d.LINE_TYPE),
d.EXPIRATION_DATE=nvl(s.EXPIRATION_DATE,d.EXPIRATION_DATE),
d.PRICE_CODE= nvl(s.PRICE_CODE,d.PRICE_CODE),
d.TO_QTY=nvl(s.TO_QTY,d.TO_QTY),
d.PRICE= nvl(s.PRICE,d.PRICE),
d.CHARGE_CODE=nvl(s.CHARGE_CODE,d.CHARGE_CODE),
d.SOC=nvl(s.SOC,d.SOC),
d.COMMITMENT=nvl(s.COMMITMENT,d.COMMITMENT),
d.CAMBIAZO_CODE=nvl(s.CAMBIAZO_CODE,d.CAMBIAZO_CODE),
d.PPG_IND=nvl(s.PPG_IND,d.PPG_IND);
This gets:
SQL Error: ORA-00905: missing keyword
00905. 00000 - "missing keyword"
If this isn't possible in 9i, then how would I do an equivalent update instead?

The syntax diagram for 9i shows that you had to have both when matched and when not matched clauses. That changed in 10gR1 (and is mentioned in the new features list); but that doesn't really help you if you can't upgrade - it just explains why it doesn't work. You were also trying to update two of the three columns from the join clause, which isn't allowed.
You can do a correlated update instead:
UPDATE CDLREFWORK.pricing d
SET (d.APPLICATION_ID, d.SYS_UPDATE_DATE, d.OPERATOR_ID, d.LOCATION_ID,
d.EXPIRATION_DATE, d.PRICE_CODE, d.TO_QTY, d.PRICE, d.CHARGE_CODE, d.SOC,
d.COMMITMENT, d.CAMBIAZO_CODE, d.PPG_IND)
= (
SELECT 'CPMASI',
SYSDATE,
nvl(s.OPERATOR_ID, d.OPERATOR_ID),
nvl(s.LOCATION_ID,d.LOCATION_ID),
nvl(s.EXPIRATION_DATE,d.EXPIRATION_DATE),
nvl(s.PRICE_CODE,d.PRICE_CODE),
nvl(s.TO_QTY,d.TO_QTY),
nvl(s.PRICE,d.PRICE),
nvl(s.CHARGE_CODE,d.CHARGE_CODE),
nvl(s.SOC,d.SOC),
nvl(s.COMMITMENT,d.COMMITMENT),
nvl(s.CAMBIAZO_CODE,d.CAMBIAZO_CODE),
nvl(s.PPG_IND,d.PPG_IND)
FROM V_REC s
WHERE s.item_id =d.item_id
AND s.line_type = d.line_type
AND s.price_code = d.price_code
)
WHERE EXISTS (
SELECT null
FROM V_REC s
WHERE s.item_id =d.item_id
AND s.line_type = d.line_type
AND s.price_code = d.price_code
);
I've taken out the item_id and line_type columns as you already know they match. The where exists clause means only rows in pricing which actually have a matching row in v_rec are updated. That may mean the nvl() calls are redundant, and you just need to select the value from s, but without knowing your data it's hard to be sure.

Related

Oracle SQL: The equivalent way to execute the following expression from PostgreSQL?

The following thread successfully showed how to use a an UPDATE SET and FROM clause together, to update an entire row of a specific column with a value derived from a different table.
When executing following expression in Oracle SQL:
UPDATE territory2_t
SET total_sales_person = t.total_count
FROM (
SELECT salesterritoryid, count(*) as total_count
FROM salesperson_t
group by salesterritoryid
) t
WHERE territoryid = t.salesterritoryid;
Oracle states: SQL Error: ORA-00933: SQL command not properly ended
In Oracle you can use merge to do the job:
merge into territory2_t
using (
SELECT salesterritoryid, count(*) as total_count
FROM salesperson_t
group by salesterritoryid
) t
on (territoryid = t.salesterritoryid)
when matched then
update SET total_sales_person = t.total_count
This can be done with MERGE (in Oracle and most other DB systems - those that implement the MERGE statement from the SQL Standard). MERGE is the preferred solution in most cases.
There is a misconception that this cannot be done with an UPDATE statement in Oracle. I show below how it can be done - not to encourage its use (MERGE is better), but to show that UPDATE can be used as well. This is the transformation of the Postgre SQL the OP solicited in the original post.
update ( select t2.total_sales_person, t.total_count
from territory2_t t2 inner join
( select salesterritoryid, count(*) as total_count
from salesperson_t
group by salesterritoryid
) t
on t2.territoryid = t.salesterritoryid
)
set total_sales_person = total_count;

Merge Query in DB2

I need to update few columns in one table with the very convoluted calculation.
I'm not good enough in SQL so I tried to use "with" clause in combination with update, but It threw error.
Then I found a post online which suggested to use MERGE so I came up with Merge query. But that one was also throwing an error.
So I removed all other column and updating only one column to remove complexity, but no avail still errors
Below is my query, select query inside working perfectly fine.
Please suggest.
MERGE INTO TABLE_1 AS O
USING (
SELECT ((TO_NUMBER(TABLE_3.Total_Whsle_Price)-TO_NUMBER(TABLE_2.OPT_BASE_WHSLE)) - ((TO_NUMBER(TABLE_3.Total_Whsle_Price)-TO_NUMBER(TABLE_2.OPT_BASE_WHSLE))*TO_NUMBER(TABLE_1.AUC_MILEAGE))/100000 ) as CORRECT_FLOOR_PRICE
FROM TABLE_1, TABLE_2,TABLE_3
WHERE TABLE_2.Primary_ID= TABLE_1.Primary_ID
AND TABLE_2.option_code = 'FSDS'
AND TABLE_1.FLOOR_PRICE <> '0.00'
and TABLE_3.Primary_ID=TABLE_1.Primary_ID
and TABLE_3.Primary_ID=TABLE_2.Primary_ID
) AS CORRECT
ON(
O.Primary_ID = CORRECT.Primary_ID
)
WHEN MATCHED THEN
UPDATE
set O.FLOOR_PRICE =CORRECT.CORRECT_FLOOR_PRICE
Error is
An error occurred when executing the SQL command:
MERGE INTO ........
DB2 SQL Error: SQLCODE=-199, SQLSTATE=42601, SQLERRMC=SELECT;VALUES, DRIVER=3.61.75 [SQL State=42601, DB Errorcode=-199]
Try this instead, I think you forgot your identifier in your select statement because after the "ON" statement "CORRECT.Primary_ID" doesn't associate to anything.
MERGE INTO TABLE_1 as O
USING (
SELECT ((TO_NUMBER(TABLE_3.Total_Whsle_Price)-TO_NUMBER
(TABLE_2.OPT_BASE_WHSLE)) - ((TO_NUMBER(TABLE_3.Total_Whsle_Price)
-TO_NUMBER(TABLE_2.OPT_BASE_WHSLE))*TO_NUMBER
(TABLE_1.AUC_MILEAGE))/100000 ) as CORRECT_FLOOR_PRICE,
TABLE_1.Primary_ID AS Primary_ID
FROM
TABLE_1, TABLE_2,TABLE_3
WHERE TABLE_2.Primary_ID = TABLE_1.Primary_ID
AND TABLE_2.option_code = 'FSDS'
AND TABLE_1.FLOOR_PRICE <> '0.00'
AND TABLE_3.Primary_ID=TABLE_1.Primary_ID
AND TABLE_3.Primary_ID=TABLE_2.Primary_ID
) AS CORRECT
ON(
O.Primary_ID = CORRECT.Primary_ID
)
WHEN MATCHED THEN
UPDATE
set O.FLOOR_PRICE = CORRECT.CORRECT_FLOOR_PRICE

Oracle - How to use merge to update a column based on the values from other table and columns

I would like to update the values in closed_date column based on the values comparison from other columns and other table. I used Oracle merge into statement. But it gave me an error:
Error: ORA-00969: missing ON keyword
I am not sure what goes wrong. Do I miss anything? Below is my script:
MERGE INTO PR_DMN dmn
USING (select alg.PR_DMN_ID, alg.PR_ACTIVITY_ID, alg.ACTIVITY_TS from PR_ACTIVITY_LOG) alg
ON dmn.PR_DMN_ID = alg.PR_DMN_ID
-- update
WHEN MATCHED THEN
UPDATE SET dmn.CLOSED_DATE =
(CASE
WHEN alg.PR_ACTIVITY_ID IN ('10009', '10010', '10011', '10013') THEN alg.ACTIVITY_TS
WHEN alg.PR_ACTIVITY_ID = '10005' AND dmn.CONT_RESP_TS <= dmn.CONT_RESP_DUE_TS THEN dmn.CONT_RESP_TS
WHEN alg.PR_ACTIVITY_ID = '10008' AND dmn.CORR_RESP_TS <= dmn.CORR_RESP_DUE_TS THEN dmn.CORR_RESP_TS
ELSE dmn.CLOSED_DATE
END)
You have two errors, as you can see with a simple example. Firstly the on clause needs to be wrapped in parenthesis. Secondly, you can't reference the alias of the sub-select in the using clause within that sub-query.
If I set up a simple example using your table names as follows:
create table pr_dmn as
select level as a, sysdate as b
from dual
connect by level <= 10;
Table created.
create table PR_ACTIVITY_LOG as
select level as a, sysdate as b
from dual
connect by level <= 20;
Table created.
Then execute the correct query it should work:
merge into pr_dmn dmn
using (select a, b from pr_activity_log) alg -- no alg. inside the sub-query
on (dmn.a = alg.a) -- wrapped in parenthesis
when matched then
update set dmn.b = alg.b
;
10 rows merged.
I always find PSOUG a good reference for things like this, though the documentation has some good examples as well.

IF-Statement in SQLite: update or insert?

I Can't run this query with SQLite
if 0<(select COUNT(*) from Repetition where (Word='behnam' and Topic='mine'))
begin
update Repetition set Counts=1+ (select Counts from Repetition where (Word='behnam' and Topic='mine'))
end
else
begin
insert Repetition(Word,Topic,Counts)values('behnam','mine',1)
end
It says "Syntax error near IF"
How can I solve the problem
SQLite does not have an IF statement (see the list of supported queries)
Insetad, check out out ERIC B's suggestion on another thread. You're effectively looking at doing an UPSERT (UPdate if the record exists, INSERT if not). Eric B. has a good example of how to do this in SQLite syntax utilizing the "INSERT OR REPLACE" functionality in SQLite. Basically, you'd do something like:
INSERT OR REPLACE INTO Repetition (Word, Topic, Counts)
VALUES ( 'behnam', 'mine',
coalesce((select Counts + 1 from Repetition
where Word = 'behnam', AND Topic = 'mine)
,1)
)
Another approach is to INSERT ... SELECT ... WHERE ... EXISTS [or not] (SELECT ...);
I do this sort of thing all the time, and I use jklemmack's suggestion as well. And I do it for other purposes too, such as doing JOINs in UPDATEs (which SQLite3 does not support).
For example:
CREATE TABLE t(id INTEGER PRIMARY KEY, c1 TEXT NOT NULL UNIQUE, c2 TEXT);
CREATE TABLE r(c1 TEXT NOT NULL UNIQUE, c2 TEXT);
INSERT OR REPLACE INTO t (id, c1, c2)
SELECT t.id, coalesce(r.c1, t.c1), coalesce(r.c2, t.c2)
FROM r LEFT OUTER JOIN t ON r.c1 = t.c1
WHERE r.c2 = #param;
The WHERE there has the condition that you'd have in your IF. The JOIN in the SELECT provides the JOIN that SQLite3 doesn't support in UPDATE. The INSERT OR REPLACE and the use of t.id (which can be NULL if the row doesn't exist in t) together provide the THEN and ELSE bodies.
You can apply this over and over. If you'd have three statements (that cannot somehow be merged into one) in the THEN part of the IF you'd need to have three statements with the IF condition in their WHEREs.
This is called an UPSERT (i.e. UPdate or inSERT). It has its forms in almost every type of database. Look at this question for the SQLite version: SQLite - UPSERT *not* INSERT or REPLACE
One way that I've found is based on SQL WHERE clause true/false statement:
SELECT * FROM SOME_TABLE
WHERE
(
SELECT SINGLE_COLUMN_NAME FROM SOME_OTHER_TABLE
WHERE
SOME_COLUMN = 'some value' and
SOME_OTHER_COLUMN = 'some other value'
)
This actually means execute some QUERIES if some other QUERY returns 'any' result.

solution for ORA-00933

I'm tring to use join but facing this issue. I've pasted my query
select count(*) from table_a inner
join table_b on table_a.number = table_b.number
left outer join table_c on table_a.id = table_c.id
and table_a.number = table_c.number
order by number;
pls let me know what is wrong in the query...
-Vinod
Are you executing this query as part of an INSERT or DELETE?
If so, remove the ORDER BY. It's not needed anyway.
Error: ORA-00933: SQL command not
properly ended
Cause: You tried to
execute an SQL statement with an
inappropriate clause.
Action: The
options to resolve this Oracle error
are:
You may have executed an INSERT
statement with an ORDER BY Clause. To
resolve this, remove the ORDER BY
clause and re-execute the INSERT
statement. For example, you tried to
execute the following INSERT
statement:
INSERT INTO supplier (supplier_id,
supplier_name) VALUES (24553, 'IBM')
ORDER BY supplier_id;
You can correct the INSERT statement
by removing the ORDER BY clause as
follows:
INSERT INTO supplier (supplier_id,
supplier_name) VALUES (24553, 'IBM');
You may have tried to execute a DELETE
statement with an ORDER BY Clause. To
resolve this, remove the ORDER BY
clause and re-execute the DELETE
statement. For example, you tried to
execute the following DELETE
statement:
DELETE FROM supplier WHERE
supplier_name = 'IBM' ORDER BY
supplier_id;
You can correct the DELETE statement
by removing the ORDER BY clause as
follows:
DELETE FROM supplier WHERE
supplier_name = 'IBM';
How did you execute this query?
In Oracle SQL, there's no such thing as a statement separator like ";". That one is only used in PL/SQL and some tools allow you to put more than one statement in a file/editor, when you separate them with ";". Only so that they can execute them separately.
Long story short: remove the ";" and try again.
Oh and next time, tell us how you ran the query. We have to check our crystal balls to guess what your problem is.
You cannot order by a value which cannot be included in the result set. your result set aggregates multiple rows, each with its own value of NUMBER, into a single row. therefore the order by does not make logical sense. In this case your query only returns one row so ORDER BY is irrelevant.
When you transcribed your query to the anodyne test case you present here you inadvertently corrected it. Well, you introduced an ORA-00918 bug but once that is fixed the code runs fine...
SQL> create table table_a (col_1 number, id number)
2 /
Table created.
SQL> create table table_b (col_1 number)
2 /
Table created.
SQL> create table table_c (col_1 number, id number)
2 /
Table created.
SQL>
SQL>
SQL> select count(*) from
2 table_a inner join table_b on table_a.col_1 = table_b.col_1
3 left outer join table_c on table_a.id = table_c.id
4 and table_a.col_1 = table_c.col_1
5 order by col_1
6 /
order by col_1
*
ERROR at line 5:
ORA-00918: column ambiguously defined
SQL> select count(*) from
2 table_a inner join table_b on table_a.col_1 = table_b.col_1
3 left outer join table_c on table_a.id = table_c.id
4 and table_a.col_1 = table_c.col_1
5 order by table_a.col_1
6 /
COUNT(*)
----------
0
SQL>
Note: I have subsituted COL_1 for NUMBER as a column name. I don't think that's your problem, because using NUMBER unescaped in the query would hurl ORA-1747 not ORA-00933.
So, let's rule out the obvious: are you running on an ancient version of Oracle which doesn't support the ANSI join syntax, that is 8i or older?