Taking out bypass_ujvc hint in 12c converting update to merge statements - sql

Hi I've been tasked with getting rid of the bypass_ujvc hint from a number of update statements as it's no longer supported in Oracle 12c, I have decided to replace the update statements with a merge statement, unluckily one of these update statements has a returning clause and a bulk collect, so i'm unsure how to approach this as a merge statement does not use a returning clause. Any advice is much appreciated. The query is below.
UPDATE /*+ bypass_ujvc */ (SELECT caco.surr_id,
caco.lead_item_yn,
caco.case_reference,
caco.logically_deleted_y
FROM TABLE (CAST(l_cc_surr_id AS db_surr_id_type_tab)) cc
JOIN case_contexts caco ON (caco.cc_surr_id = cc.COLUMN_VALUE)
JOIN cases cas ON (cas.REFERENCE = caco.case_reference )
WHERE caco.logically_deleted_y IS NULL
AND cas.status IN ('INP', 'TOS'))
SET logically_deleted_y = 'Y'
RETURNING surr_id, lead_item_yn, case_reference
BULK COLLECT INTO l_caco_surr_id, l_lead_item, l_all_cases;

An approach using bulk collect and forall would look something like this:
begin
select caco.surr_id, caco.lead_item_yn, caco.case_reference
bulk collect into l_caco_surr_id, l_lead_item, l_all_cases
from table(l_cc_surr_id) cc
join case_contexts caco on caco.cc_surr_id = cc.column_value
join cases cas on cas.reference = caco.case_reference
where caco.logically_deleted_y is null
and cas.status in ('INP', 'TOS');
forall i in 1..l_caco_surr_id.count
update case_contexts
set logically_deleted_y = 'Y'
where surr_id = l_caco_surr_id(i);
end;
You might want to put that in a loop with a limit clause, but this should give the general idea.

Related

Snowfalke sql update if exists else insert

I have looked at other question but seems that snowflake doesn't support if/else in sql, at least not the way that other sql servers support it.
some suggested to use javascript but i would like to avoid that if I can.
I am trying to Insert into a table using snowflake python library some data, if it's already there then I would like to update the data, I have looked at merge but it doesn't seem to fit me since my data isn't a table
that's what I have so far that isn't working
f"""BEGIN
IF (EXISTS (SELECT * FROM {self.okr_table} WHERE kpi=TRUE AND Month(month)=MONTH(current_date()) AND year(month)=YEAR(current_date())))
THEN
UPDATE {self.okr_table} SET [DATA] = {json.dumps(self.data)} WHERE kpi=TRUE AND Month(month)=MONTH(current_date()) AND year(month)=YEAR(current_date()))
ELSE
INSERT INTO {self.okr_table} (month, data, kpi) SELECT current_date(),parse_json('{json.dumps(self.data)}'), true;
END"""
To perfrom INSERT/UPDATE it is better to use single MERGE statement
I have looked at merge but it doesn't seem to fit me since my data isn't a table
It is not an issue as source could be a table or subquery:
MERGE INTO {self.okr_table}
USING (SELECT PARSE_JSON({json.dumps(self.data)} AS data
, MONTH(current_date()) AS month
, YEAR(current_date()) AS year
) s
ON {self.okr_table}.KPI
AND MONTH({self.okr_table}.month) = s.month
AND YEAR({self.okr_table}.month) = s.year
WHEN MATCHED THEN UPDATE
WHEN NOT MATCHED THEN INSER ...;
IF/ELSE branching works in Snowflake:
BEGIN
IF (EXISTS (...)) THEN
UPDATE ... ;
ELSE
INSERT ... ;
END IF;
END;
Please note ; after each statement, END IF and parenthesis around condition.

DB2 SQL considers IF ELSE condition a DDL statement?

I am trying to use a simple IF ELSE query to test a feature with DB2 SQL. However when I attempt to execute it, I run into an error stating that I am not allowed to execute DDL statements.
What is throwing me off is that as far as I know, only database structure altering statements are considered DDL statements.
What gives?
Code:
IF 'True' = 'True' THEN
SELECT * FROM RM_TRANSACTION
FETCH FIRST 2 ROWS ONLY
FOR READ ONLY WITH UR
ELSE
SELECT * FROM RM_TRANSACTION
FETCH FIRST 4 ROWS ONLY
FOR READ ONLY WITH UR
END IF
https://imgur.com/a/58RYjpu
The problem is that you can’t ‘select to nowhere’ in a compound statement in DB2. Db2 CLP can return you the result set of a single sql statement, but it doesn’t try to do the same for select statements in a compound statement.
If you want to print the result set from a select statement in a compound statement, you can, for example, declare a cursor, fetch it in a loop, and use dbms_output.put_line calls to print the values of variables.

Merge statement for first time insert

I did some research and couldn't find any solution and hence posting it here.
We have a dataload job which runs on a daily basis. We have separate DML statements to insert, update etc. We wanted to avoid insert statements to run multiple times.
Is there an option to use merge statement in this scenario to update if the record is present or insert if not present?
Please give me an example if possible as I am quite new to sql statements.
We are using Oracle db2 for dbms
Thanks in advance!
Use an IF EXISTS statement, like this:
IF EXISTS (SELECT 1 FROM #mytable# WHERE #column1# = #this# AND #column2# = #that)
BEGIN
#update statement#
END
ELSE
BEGIN
#insert statement#
END
EDIT:
the syntax for this can be found here: https://www.toadworld.com/platforms/ibmdb2/w/wiki/7777.ifthenelse
this means that my general case would become this in DB2:
IF (#count of value# = 1) THEN
#updatestatement#;
ELSEIF (#count of value# > 1) THEN
#throw an error, as you cannot update uniquely#
ELSE
#insertstatement#;
END IF;
I also noticed that you can run SQL commands on DB2, which might be useful for this task as well
finally, have a look here, might give you further ideas :)
DB2 for IBM iSeries: IF EXISTS statement syntax
Got it done throught Merge statements itself :)
MERGE INTO table1(storeent_id, name, value) AS t1
USING (VALUES ((SELECT STOREENT_ID FROM STOREENT WHERE IDENTIFIER='test'), 'SOLR_SERVICEABILITY_URL',
'Sample')) AS t2(storeent_id, name, value)
ON t1.name = t2.name AND t1.storeent_id = t2.storeent_id
WHEN MATCHED THEN
UPDATE SET
t1.value = t2.value
WHEN NOT MATCHED THEN
INSERT
(name, storeent_id, value)
VALUES (t2.name, t2.storeent_id, t2.value);

Select all record from all the tables, every derived table must have its own alias

I'm working on a e-learning project in which there is a table named chapter in which there is a column named question_table this is table in which the specific chapter's questions are added.
Now the problem is I want to display all the question from all the chapter for this I used following sql query
SELECT * FROM (SELECT `question_table` FROM `chapter`)
but it doesn't work and gives the error:
"Every derived table must have its own alias".
Note: I want to do it using SQL not PHP.
Firstly, I think you would be better redesigning your database. Multiple tables of the same structure holding the same data are generally not a good idea.
However what you require is possible using a MySQL procedure to build up some dynamic SQL and then execute it, returning the resulting data.
A procedure as follows could be used to do this:-
DROP PROCEDURE IF EXISTS dynamic;
delimiter //
CREATE PROCEDURE dynamic()
BEGIN
DECLARE question_table_value VARCHAR(25);
DECLARE b INT DEFAULT 0;
DECLARE c TEXT DEFAULT '';
DECLARE cur1 CURSOR FOR SELECT `question_table` FROM `chapter`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET b = 1;
OPEN cur1;
SET b = 0;
WHILE b = 0 DO
FETCH cur1 INTO question_table_value;
IF b = 0 THEN
IF c = '' THEN
SET c = CONCAT('SELECT * FROM `',question_table_value, '`');
ELSE
SET c = CONCAT(c, ' UNION SELECT * FROM `',question_table_value, '`');
END IF;
END IF;
END WHILE;
CLOSE cur1;
SET #stmt1 := c;
PREPARE stmt FROM #stmt1;
EXECUTE stmt;
END
This is creating a procedure called dynamic. This takes no parameters. It sets up a cursor to read the question_table column values from the chapter table. It looks around the results from that, building up a string which contains the SQL, which is a SELECT from each table with the results UNIONed together. This is then PREPAREd and executed. The procedure will return the result set from the SQL executed by default.
You can call this to return the results using:-
CALL dynamic()
Down side is that this isn't going to give nice results if there are no rows to return and they are not that easy to maintain or debug with the normal tools developers have. Added to which very few people have any real stored procedure skills to maintain it in future.
In MySQL you must give every subquery ("derived table") an alias:
SELECT * FROM (SELECT question_table FROM chapter) t --notice the alias "t"
The derived table here is the result of the (SELECT ...). You need to give it an alias, like so:
SELECT * FROM (SELECT question_table FROM chapter) X;
Edit, re dynamic tables
If you know all the tables in advance, you can union them, i.e.:
SELECT * FROM
(
SELECT Col1, Col2, ...
FROM Chapter1
UNION
SELECT Col1, Col2, ...
FROM Chapter2
UNION
...
) X;
SqlFiddle here
To do this solution generically, you'll need to use dynamic sql to achieve your goal.
In general however, this is indicative of a smell in your table design - your chapter data should really be in one table, and e.g. classified by the chapter id.
If you do need to shard data for scale or performance reasons, the typical mechanism for doing this is to span multiple databases, not tables in the same database. MySql can handle large numbers of rows per table, and performance won't be an issue if the table is indexed appropriately.

Testing For Primary Key Existence In Oracle SQL Trigger

I'm trying to write a trigger within SQL, and the code within needs to determine whether an entry exists in the table before either attempting to update, or insert.
I have tried using both
IF EXISTS
UPDATE
ELSE
INSERT
And
UPDATE
IF ##ROWCOUNT = 0
INSERT
But neither of them work. I'm partial to using the latter because my employer is nuts about efficiency (well...duh...) For this reason I'm also reluctant to use
IF SELECT COUNT(*) = 0
UPDATE
ELSE
INSERT
Does anybody know any ways to get around this?
--
UPDATE: I am trying to use MERGE, but I am receiving several errors...
MERGE INTO [tableName] AS Target
USING (SELECT :NEW.PIDM) AS Source (PIDM)
ON (Target.PIDM = Source.PIDM)
WHEN MATCHED THEN
[UPDATE STATEMENT]
WHEN NOT MATCHED THEN
[INSERT STATEMENT]
This gives me an error complaining that I'm missing the 'USING' keyword, as well as another complaining about the WHEN statement...
Use MERGE instead
In PL/SQL, you would use SQL%ROWCOUNT instead of ##ROWCOUNT:
UPDATE (...);
IF SQL%ROWCOUNT = 0 THEN
INSERT (...);
END IF;
Or, you could use SQL%NOTFOUND, which I personally think is easier to understand the intent:
UPDATE (...);
IF SQL%NOTFOUND THEN
INSERT (...);
END IF;
As for the MERGE command, the Oracle syntax is slightly different from the SQL Server which #zerkms linked to. In particular, you should leave the word "AS" out of the table alias, and you shouldn't list columns after the "USING" clause. Also, in Oracle SQL, the FROM clause is mandatory. You can use the DUAL table to mimic SQL Server's behavior. Putting it all together (this is untested):
MERGE INTO tableName Target
USING (SELECT :NEW.PIDM FROM DUAL) Source
ON (Target.PIDM = Source.PIDM)
WHEN MATCHED THEN
[UPDATE STATEMENT]
WHEN NOT MATCHED THEN
[INSERT STATEMENT]