problem in instead of delete views in oracle - database

I have a view as:
select * from ot.vw_rebellionrid;
which is showing me:
full_name is column of trainer table
subject_name is column of subject table
The view has the query:
SELECT full_name, subject_name
FROM ot.trainer, ot.subject;
So,I am learning the instead of delete tigger,so the code for instead of trigger is:
CREATE OR REPLACE TRIGGER ot.io_delete
INSTEAD OF DELETE ON ot.vw_RebellionRid
FOR EACH ROW
BEGIN
DELETE FROM ot.trainer WHERE FULL_NAME = :old.FULL_NAME;
DELETE FROM ot.subject WHERE SUBJECT_NAME= :old.SUBJECT_NAME;
END;
/
So,to execute this trigger,I execute the following statement:
delete from ot.vw_RebellionRid where subject_name='java';
when it is executed,then :
2 rows deleted.
According to my understanding,Since the two rows has subject_name as java the remaining output,I think will be after the deletion:
--------------------------
full_name | subject_ name |
---------------------------
Manish Sharma Oracle |
ashwin Oracle |
---------------------------
But when I executed
select * from ot.vw_RebellionRid ;
then,I got the output as EMPTY TABLE;
Since,there were 4rows,2rows were deleted,but when i again select the view then how I am getting empty table?I should have got remaining two rows.

I think your trigger is working perfectly.
DELETE FROM ot.trainer WHERE FULL_NAME = :old.FULL_NAME;
It will delete 2 rows having name manish and ashwin as both are tagged with java.
The same way,
DELETE FROM ot.subject WHERE SUBJECT_NAME= :old.SUBJECT_NAME;
It will delete subject java from table subject so now table subject will have 1 record remaining i.e.Oracle
Now, your view query will join between 2 tables (trainer table with 0 rows and subject table with 1 rows) so it is producing no result.
You need to understand that,
delete from ot.vw_RebellionRid where subject_name='java';
is deleting total 3 records.
Cheers!!

The problem is that when debugging your problem you didn't follow through. Your INSTEAD OF DELETE trigger certainly deleted SOMETHING, but to determine what was deleted you need to look at the tables underlying the view. If you perform your DELETE statement and then examine the contents of TRAINER and SUBJECT you'll find that the only thing left is the Oracle row in SUBJECT. And if you look at your trigger and think about what you told it to do you'll realize it did exactly what you told it to do, even if that might not have been what you wanted.
dbfiddle here

Related

Delete Records Based on Query Output

I have a table, THEKITCHEN with a query:
SELECT FOOD, COUNT(FOOD)
FROM THEKITCHEN
GROUP BY FOOD
This returns an output of:
FOIEGRAS 1
APPLEPIE 1
SORBET 1
FILETMIGNON 1
BRANZINO 5
TRUFFLES 2
ESCARGO 1
POULET 2
And what I do next is delete items using the following:
DELETE FROM THEKITCHEN
WHERE FOOD IN ('FOIEGRAS')
Now this works but sometimes I need to delete all items/records in that column. And running that DELETE statement 15-40 times becomes annoying.
Is it possible to get the output of the initial query into a variable and then use the DELETE statement on that variable to delete all the items? I've tried
UPDATE THEKITCHEN
SET FOOD = NULL;
But that errored in that my table doesn't allow Null.
Thanks!
Update: THEKITCHEN has other columns which I do not want to delete records from. So TRUNCATE TABLE THEKITCHEN would lose a lot of important stuff.
Update: Yes TRUNCATE TABLE THEKITCHEN is the way to go!
If you want to delete all the food items, you don't need a condition at all, just use delete from thekitchen. Moreover, you can use a DDL statement truncate table thekitchen which would be much faster.

How to get data from the current row in INSTEAD OF trigger?

For example, we have a table named 'Names':
id | name
-----+------
1 | Mary
2 | Sue
3 | John
and this trigger:
CREATE TRIGGER TRG_insofdel
ON Names
INSTEAD OF DELETE
AS
BEGIN
-- here I need to get some data from the current row
END
and then I call
DELETE FROM Names
WHERE id = 1
How can I get Mary's (id == 1) name in the trigger?
What is going on with the 'deleted' table in this case?
The MSDN documentation does explain but it isn't laid out very clearly.
In a trigger, SQL server automatically makes 2 special in-memory tables available to you:
inserted: the data which was added to the table (for insert and update statements)
deleted: the data which was removed from the table (for update and delete statements)
They have the same columns as the actual table, but are completely read-only - you cannot add columns or indexes to them or change the data inside them.
So in your example, to get the name of the person being removed, you can do the following inside the trigger:
DECLARE #name varchar(100);
SELECT #name = name from deleted;
Important note
Be aware tho that if multiple rows were deleted from the table, then deleted will contain multiple rows - the trigger is not called individually once for each row.

How to safely use current identity as value in insert query

I have a table where one of the columns is a path to an image and I need to create a directory for the record being inserted.
Example:
Id | PicPath |<br>
1 | /Pics/1/0.jpg|<br>
2 | /Pics/2/0.jpg|
This way I can be sure that the folder name is always valid and it is unique (no clash between two records).
Question is: how can I safely refer to the current id of the record being insert? Keep in mind that this is a highly concurrent environment, and I would like to avoid multiple trips to the DB if possible.
I have tried the following:
insert into Dummy values(CONCAT('a', (select IDENT_CURRENT('Dummy'))))
and
insert into Dummy values(CONCAT('a', (select SCOPE_IDENTITY() + 1)))
The first query is not safe, for when running 1000 concurrent inserts I got 58 'duplicate key' exceptions.
The second query didn't work because SCOPE_IDENTITY() returned the same value for all queries as I suspected.
What are my alternatives here?
Try a temporary table to track your inserted ids using OUTPUT clause
INSERT #temp_ids(someval) OUTPUT inserted.identity_column
This will get all the inserted ids from your queries. 'inserted' is context safe.

Merge query using two tables in SQL server 2012

I am very new to SQL and SQL server, would appreciate any help with the following problem.
I am trying to update a share price table with new prices.
The table has three columns: share code, date, price.
The share code + date = PK
As you can imagine, if you have thousands of share codes and 10 years' data for each, the table can get very big. So I have created a separate table called a share ID table, and use a share ID instead in the first table (I was reliably informed this would speed up the query, as searching by integer is faster than string).
So, to summarise, I have two tables as follows:
Table 1 = Share_code_ID (int), Date, Price
Table 2 = Share_code_ID (int), Share_name (string)
So let's say I want to update the table/s with today's price for share ZZZ. I need to:
Look for the Share_code_ID corresponding to 'ZZZ' in table 2
If it is found, update table 1 with the new price for that date, using the Share_code_ID I just found
If the Share_code_ID is not found, update both tables
Let's ignore for now how the Share_code_ID is generated for a new code, I'll worry about that later.
I'm trying to use a merge query loosely based on the following structure, but have no idea what I am doing:
MERGE INTO [Table 1]
USING (VALUES (1,23-May-2013,1000)) AS SOURCE (Share_code_ID,Date,Price)
{ SEEMS LIKE THERE SHOULD BE AN INNER JOIN HERE OR SOMETHING }
ON Table 2 = 'ZZZ'
WHEN MATCHED THEN UPDATE SET Table 1.Price = 1000
WHEN NOT MATCHED THEN INSERT { TO BOTH TABLES }
Any help would be appreciated.
http://msdn.microsoft.com/library/bb510625(v=sql.100).aspx
You use Table1 for target table and Table2 for source table
You want to do action, when given ID is not found in Table2 - in the source table
In the documentation, that you had read already, that corresponds to the clause
WHEN NOT MATCHED BY SOURCE ... THEN <merge_matched>
and the latter corresponds to
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
Ergo, you cannot insert into source-table there.
You could use triggers for auto-insertion, when you insert something in Table1, but that will not be able to insert proper Shared_Name - trigger just won't know it.
So you have two options i guess.
1) make T-SQL code block - look for Stored Procedures. I think there also is a construct to execute anonymous code block in MS SQ, like EXECUTE BLOCK command in Firebird SQL Server, but i don't know it for sure.
2) create updatable SQL VIEW, joining Table1 and Table2 to show last most current date, so that when you insert a row in this view the view's on-insert trigger would actually insert rows to both tables. And when you would update the data in the view, the on-update trigger would modify the data.

delete duplicate rows

anyone know how can i delete duplicate rows by writing new way from script below to improve performance.
DELETE lt1 FROM #listingsTemp lt1, #listingsTemp lt2
WHERE lt1.code = lt2.code and lt1.classification_id > lt2.classification_id and (lt1.fap < lt2.fap or lt1.fap = lt2.fap)
Delete Duplicate Rows in a SQL Table :
delete table_a
where rowid not in
(select min(rowid) from table_a
group by column1, column2);
1 - Create an Identity Column (ID) for your table (t1)
2 - Do a Group by on your table with your conditions and get IDs of duplicated records.
3 - Now, simply Delete records from t1 where IDs IN duplicated IDs set.
Look into BINARY_CHECKSUM .... you could possibly use it when creating your temp tables to more quickly determine if the data is the same.... for example create a new field in both temp tables storing the binary_checksum value... then just delete where those fields equal
The odiseh answer seems to be valid (+1), but if for some reason you can't alter the structure of the table (because you have not the code of the applications that are using it or something) you could write a job that run every night and delete the duplicates (using the Moayad Mardini code).

Resources