I want the trigger to run after each and every record that gets inserted.
This validation works fine if I have a simple insert like this:
insert into g_dossier values
(112334, 'BBT', 'LPO','TTS','Y') ;
However, when it’s like a bulk insert like this:
INSERT INTO g_piece(
refpiece,
typpiece,
class_piece
group_piece
flag_piere)
SELECT :new.element_num,
PROC_TYPE,
DECODE( piece_it, 'F', 'FTTR', 'N', 'FTTR', NULL ),
DECODE( piece_it, 'T', 'TTSN', 'N', 'TTSN', NULL ),
'N'
FROM t_elements
WHERE :new.db_piece_flag = 'Y';
The trigger mutates. I want that the validation also work when done as a bulk insert.
The query causing this problem is
SELECT COUNT(*)
INTO existing_cmcl_cnt
FROM g_piece cmcl
WHERE cmcl.class_piece= :new.class_piece
The problem is that this query is called in a trigger applied on the same table "g_piece". When I proceed with a simple insert (insert into g_piece values(...)), I do not have this problem.
How can I avoid this problem?
Thanks.
Here you should change the query and insert the result of a SELECT ... FROM some join, not using a trigger at all. You want that when inserting into table X, a trigger also inserts into the same table, which is not possible (it would recurse).
If you cannot change the query, you should rename your table, create a view to the table with the old name, and create a TRIGGER INSTEAD OF INSERT ON that view FOR EACH ROW
that would INSERT INTO into the real table the result of a SELECT ... FROM some join.
If you're using Oracle 11G, you can take a look to Compound triggers to avoid the mutating-table error. Take a look:
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD
Related
I am miserably failing to build a sql trigger (in background) where I want to insert data from one table to another if a certain condition is met, something like this:
Create trigger on table Invoice
If inv_number starts with inv
Then Insert into Document (var1,var2,var3) values (inv_number, inv_date, inv_amount)
Thanks
If you're using SQL Server (as I said in comments - triggers are highly vendor-specific, so if you're using something else, you'll have to adapt as needed), you can use something like this:
CREATE TRIGGER trgInvoiceInsert
ON dbo.Invoice
AFTER INSERT -- adapt if you need to run this after UPDATE or DELETE, too
AS
BEGIN
/* In SQL Server, if you inserting a bunch of rows
at once using an `INSERT INTO .... SELECT ....`
approach, then this trigger will be called only *ONCE*,
with all the inserted rows in the "Inserted" pseudo table.
Handle it accordingly - in a set-based manner
*/
INSERT INTO dbo.Document (col1, col2, col3)
SELECT i.inv_number, i.inv_date, i.inv_amount)
FROM Inserted i
WHERE i.inv_number LIKE 'inv%'
END
For further details, check out the official Microsoft documentation on SQL Server triggers
I am trying to insert values into 1 column of a table when a condition is satisfied.
Note: The table already contains data for all the columns but for 1 which is empty. I would like to insert value into this 1 column depending on the WHERE clause.
I have this query:
INSERT INTO <TABLE_NAME>
(COLUMN_NAME)
(VALUE)
WHERE <CONDITION>
I am getting an exception:
Incorrect Syntax Near WHERE Keyword
I am able to do this using UPDATE:
UPDATE <TABLE_NAME>
SET <COL_NAME>
WHERE <CONDITION>
But was wondering why the INSERT query was failing. Any advise appreciated.
As I understand your problem, you already have data in one row, and one column in that row does not have value, so you want to add value in to that column.
This the scenario for Update existing row, not the insert new row. You have to use UPDATE clause when data already present and you want to modify record(s). Choose insert when You want to insert new row in table.
So in your current scenario, Update Clause is your friend with Where Clause as you want to modify subset of records not all.
UPDATE <TABLE_NAME>
SET <COL_NAME>
WHERE <CONDITION>
INSERT Clause does not have any Where Clause as per any RDBMS syntax(I think). Insert is condition less sql query, While SELECT, UPDATE, DELETE all are conditional commands, you can add Where Clause in all later ones.
In order to add a value into the one column when the rows are already populated, you will need to use the update statement.
If you need to insert a new row that has a where clause, you will need to use an insert into select statement:
INSERT INTO <table> (<columns>)
SELECT <columns>
FROM <table>
WHERE <condition>;
The SQL Insert dont accept where parameters, you could check this: SQL Insert Definition...
I do not know the whole question of what you want to do, but just using the INSERT statement is not possible, however it is possible to condition the insertion of data into a table, if this data is dependent on another table or comes from another table ... check here... SQL Insert explain in wikipedia
like this:
Copying rows from other tables
INSERT INTO phone_book2
SELECT *
FROM phone_book
WHERE name IN ('John Doe', 'Peter Doe')
or
INSERT INTO phone_book2 ( [name], [phoneNumber] )
SELECT [name], [phoneNumber]
FROM phone_book
WHERE name IN ('John Doe', 'Peter Doe')
Based on your question I have the feeling that you are trying to UPDATE a column in a table rather than insert.
Something like:
UPDATE column SET value WHERE different_column_value = some_value
I know this is kinda late, for those who still want to use the where clause in an insert query, it's kinda possible with a hack.
My understanding is that, you want to insert only if a condition is true. Let's assume you have a column in your database "surname" and you want to insert only if a surname doesn't exist from the table.
You kinda want something like INSERT INTO table_name blha blha blah WHERE surname!="this_surname".
The solution is to make that cell unique from your admin panel.
Insert statement will insert a new record. You cannot apply a where clause to the record that you are inserting.
The where clause can be used to update the row that you want.
update SET = where .
But insert will not have a where clause.
Hope this answers your question
INSERT syntax cannot have WHERE clause. The only time you will find INSERT has WHERE clause is when you are using INSERT INTO...SELECT statement.
I take it the code you included is simply a template to show how you structured your query. See the SO questions here, here and the MSDN question here.
In SQL Server (which uses Transact-SQL aka T-SQL) you need an UPDATE query for INSERT where columns already have values - by using the answer #HaveNoDisplayName gave :)
If you are executing INSERT / UPDATE from code (or if you need it regularly) I would strongly recommend using a stored procedure with parameters.
You could extend the procedure further by adding an INSERT block to the procedure using an IF-ELSE to determine whether to execute INSERT new record or UPDATE an existing, as seen in this SO answer.
Finally, take a look at SQLFiddle for a sandbox playground to test your SQL without risk to your RDMS :-)
Private case I found useful: Conditional insert which avoids duplications:
-- create a temporary table with desired values
SELECT 'Peter' FirstName, 'Pan' LastName
INTO #tmp
-- insert only if row doesn't exist
INSERT INTO Persons (FirstName, LastName)
SELECT *
FROM #tmp t
WHERE NOT EXISTS (SELECT * FROM Persons where FirstName=t.FirstName and LastName=t.LastName)
If the data need to be added for a column for an existing row then it’s UPDATE.
INSERT is creating a new row in the table.
For conditional INSERT, you can use the MERGE command.
I have a site using the asp.net membership schema. I'd like to set up a trigger on the aspnet_users table that inserted the user_id and the user_name of the new row into another table.
How do I go about getting the values from the last insert?
I can select by the last date_created but that seems smelly. Is there a better way?
try this for sql server
CREATE TRIGGER yourNewTrigger ON yourSourcetable
FOR INSERT
AS
INSERT INTO yourDestinationTable
(col1, col2 , col3, user_id, user_name)
SELECT
'a' , default , null, user_id, user_name
FROM inserted
go
You use an insert trigger - inside the trigger, inserted row items will be exposed as a logical table INSERTED, which has the same column layout as the table the trigger is defined on.
Delete triggers have access to a similar logical table called DELETED.
Update triggers have access to both an INSERTED table that contains the updated values and a DELETED table that contains the values to be updated.
You can use OLDand NEW in the trigger to access those values which had changed in that trigger. Mysql Ref
In a SQL Server trigger you have available two psdeuotables called inserted and deleted. These contain the old and new values of the record.
So within the trigger (you can look up the create trigger parts easily) you would do something like this:
Insert table2 (user_id, user_name)
select user_id, user_name from inserted i
left join table2 t on i.user_id = t.userid
where t.user_id is null
When writing triggers remember they act once on the whole batch of information, they do not process row-by-row. So account for multiple row inserts in your code.
When you are in the context of a trigger you have access to the logical table INSERTED which contains all the rows that have just been inserted to the table. You can build your insert to the other table based on a select from Inserted.
Create
trigger `[dbo].[mytrigger]` on `[dbo].[Patients]` after update , insert as
begin
--Sql logic
print 'Hello world'
end
I have code snippet in my PL/SQL procedure that does the following:
INSERT INTO payment_operations (id, subscriber, amount, description) VALUES (payment_id, 1234, 5, 'Test');
COMMIT;
SELECT subscriber INTO test_subscriber FROM payment_operations_view WHERE id = payment_id;
After this I get an exception "no_data_found"! However, if I do the same SELECT statement myself after running the procedure, I see the record.
Note that I am selecting from a view, and not directly from the table. Why I cannot see this data right after insertion?
This is a hunch:
Does the payment_options table have a column payment_id?
I ask because in the following statement, within PL/SQL, if payment_id exists as a column, then the column is going to be used not the local PL/SQL variable:
SELECT subscriber
INTO test_subscriber
FROM payment_operations_view
WHERE id = payment_id;
Since it is using the payment_id column, if it exists, and since it was not set in the insert you might be doing where id = null which never evaluates to true.
I use v_ to signify variables. So your snippet would become (with the rest of the procedure changed accordinly):
INSERT INTO payment_operations (id, subscriber, amount, description)
VALUES (v_payment_id, 1234, 5, 'Test');
COMMIT;
SELECT subscriber
INTO v_test_subscriber
FROM payment_operations_view WHERE id = v_payment_id;
Looks like the view you are referring to is a 'materialized' view. If yes, try this code snippet to refresh the view manually before you fetch the data:
...
INSERT INTO payment_operations (id, subscriber, amount, description) VALUES (payment_id, 1234, 5, 'Test');
COMMIT;
DBMS_SNAPSHOT.REFRESH( 'payment_operations_view','c');
SELECT subscriber INTO test_subscriber FROM payment_operations_view WHERE id = payment_id;
DBMS_OUTPUT.PUT_LINE('--> ' || test_subscriber);
...
Hope this helps.
You're inserting into the base table, then selecting from a view. Does the view have any filter conditions? If so, it's possible that the data you've inserted simply doesn't match the view's conditions.
As others have pointed out, it's also possible that the view is a materialized view, in which case it may need to be refreshed.
I have to ask ... why does the logic require selecting out data you've just inserted anyway? Unless you expect something else to have modified the data between the INSERT and SELECT, why not just use the subscriber value that you just inserted instead of querying to get it again?
Explicitly put a commit after the insert statement and check.
To me it appears that select statement is running before the commit actually happens after insert.
From my code (Java) I want to ensure that a row exists in the database (DB2) after my code is executed.
My code now does a select and if no result is returned it does an insert. I really don't like this code since it exposes me to concurrency issues when running in a multi-threaded environment.
What I would like to do is to put this logic in DB2 instead of in my Java code.
Does DB2 have an insert-or-update statement? Or anything like it that I can use?
For example:
insertupdate into mytable values ('myid')
Another way of doing it would probably be to always do the insert and catch "SQL-code -803 primary key already exists", but I would like to avoid that if possible.
Yes, DB2 has the MERGE statement, which will do an UPSERT (update or insert).
MERGE INTO target_table USING source_table ON match-condition
{WHEN [NOT] MATCHED
THEN [UPDATE SET ...|DELETE|INSERT VALUES ....|SIGNAL ...]}
[ELSE IGNORE]
See:
http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=/com.ibm.db2.udb.admin.doc/doc/r0010873.htm
https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0010873.html
https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/merge?lang=en
I found this thread because I really needed a one-liner for DB2 INSERT OR UPDATE.
The following syntax seems to work, without requiring a separate temp table.
It works by using VALUES() to create a table structure . The SELECT * seems surplus IMHO but without it I get syntax errors.
MERGE INTO mytable AS mt USING (
SELECT * FROM TABLE (
VALUES
(123, 'text')
)
) AS vt(id, val) ON (mt.id = vt.id)
WHEN MATCHED THEN
UPDATE SET val = vt.val
WHEN NOT MATCHED THEN
INSERT (id, val) VALUES (vt.id, vt.val)
;
if you have to insert more than one row, the VALUES part can be repeated without having to duplicate the rest.
VALUES
(123, 'text'),
(456, 'more')
The result is a single statement that can INSERT OR UPDATE one or many rows presumably as an atomic operation.
This response is to hopefully fully answer the query MrSimpleMind had in use-update-and-insert-in-same-query and to provide a working simple example of the DB2 MERGE statement with a scenario of inserting AND updating in one go (record with ID 2 is updated and record ID 3 inserted).
CREATE TABLE STAGE.TEST_TAB ( ID INTEGER, DATE DATE, STATUS VARCHAR(10) );
COMMIT;
INSERT INTO TEST_TAB VALUES (1, '2013-04-14', NULL), (2, '2013-04-15', NULL); COMMIT;
MERGE INTO TEST_TAB T USING (
SELECT
3 NEW_ID,
CURRENT_DATE NEW_DATE,
'NEW' NEW_STATUS
FROM
SYSIBM.DUAL
UNION ALL
SELECT
2 NEW_ID,
NULL NEW_DATE,
'OLD' NEW_STATUS
FROM
SYSIBM.DUAL
) AS S
ON
S.NEW_ID = T.ID
WHEN MATCHED THEN
UPDATE SET
(T.STATUS) = (S.NEW_STATUS)
WHEN NOT MATCHED THEN
INSERT
(T.ID, T.DATE, T.STATUS) VALUES (S.NEW_ID, S.NEW_DATE, S.NEW_STATUS);
COMMIT;
Another way is to execute this 2 queries. It's simpler than create a MERGE statement:
update TABLE_NAME set FIELD_NAME=xxxxx where MyID=XXX;
INSERT INTO TABLE_NAME (MyField1,MyField2) values (xxx,xxxxx)
WHERE NOT EXISTS(select 1 from TABLE_NAME where MyId=xxxx);
The first query just updateS the field you need, if the MyId exists.
The second insertS the row into db if MyId does not exist.
The result is that only one of the queries is executed in your db.
I started with hibernate project where hibernate allows you to saveOrUpdate().
I converted that project into JDBC project the problem was with save and update.
I wanted to save and update at the same time using JDBC.
So, I did some research and I came accross ON DUPLICATE KEY UPDATE :
String sql="Insert into tblstudent (firstName,lastName,gender) values (?,?,?)
ON DUPLICATE KEY UPDATE
firstName= VALUES(firstName),
lastName= VALUES(lastName),
gender= VALUES(gender)";
The issue with the above code was that it updated primary key twice which is true as
per mysql documentation:
The affected rows is just a return code. 1 row means you inserted, 2 means you updated, 0 means nothing happend.
I introduced id and increment it to 1. Now I was incrementing the value of id and not mysql.
String sql="Insert into tblstudent (id,firstName,lastName,gender) values (?,?,?)
ON DUPLICATE KEY UPDATE
id=id+1,
firstName= VALUES(firstName),
lastName= VALUES(lastName),
gender= VALUES(gender)";
The above code worked for me for both insert and update.
Hope it works for you as well.