I have a stored procedure that inserts multiple rows into a table via a USER defined tyble. The user defined type is populated from a c# datatable.
Within the stored procedure, before the insert command with the datatable executes, I have another insert command into another table. Scope_Identity() to grab the ID of the newly inserted row and assign it to a variable.
What I would like to do is add that ID to all the rows that are added with the User defined type.
What's the best way to do this? How can I incorporate the Scope_Identity value into the insert statement?
If I am not mistaken, you can set the SCOPE_IDENTITY to an integer variable and use it in your INSERT
DECLARE #lastId INT
-- Your first INSERT
INSERT INTO yourTable1 ....
SET #lastId = SCOPE_IDENTITY()
-- Your second INSERT
INSERT INTO yourTable2(...)
VALUES(#lastId, [user data types], ...)
Related
I'm trying to get a trigger in phpmyadmin which would create a audit with a certain column value (reputation) before and after the update of a specific table.
Something like:
CREATE DEFINER=`test`#`%`
TRIGGER `monitor update reputation`
BEFORE UPDATE ON `game_resorts`
FOR EACH ROW
INSERT INTO `audit` (`id`, `datetime`, `id_resort`, `reputation`)
VALUES (NULL, CURRENT_TIMESTAMP, id_resort, reputation)
The main question is how can I retrieve the id_resort which will be updated; and then, the reputation value?
In MySQL, you would use the NEW keyword, so I assume it would be the same using phpmyadmin.
For example:
CREATE DEFINER=`test`#`%`
TRIGGER `monitor_update_reputation` //don't use spaces in a trigger name
BEFORE UPDATE ON `game_resorts`
FOR EACH ROW
INSERT INTO `audit` (`datetime`, `id_resort`, `reputation`)
VALUES (CURRENT_TIMESTAMP, NEW.id_resort, NEW.reputation)
If you want to get the value of id_resort or reputation before the update, you can use the OLD keyword:
...
VALUES (CURRENT_TIMESTAMP, OLD.id_resort, OLD.reputation)
Also, I don't think you can insert NULL into a primary key column. If your id on the audit table is set to auto increment, you can simply omit the id column from the INSERT statement.
I have tree tables in a database: users (user_id (auto increment), fname, lname), roles (role_id, role_desc) and users_roles (user_id, role_id). What I'd like to do is to have a function create_user_with_role. The function takes 3 arguments: first name, last name and role_id. The function inserts a new row into the users table and a new user_id is created automatically. Now I want to insert a new record to the users_roles table: user_id is the newly created value and the role_id is taken from the function's arguments list.
Is it possible to pass the role_id argument to an after insert trigger (defined on users table) so another automatic insert can be performed? Or can you suggest any other solution?
First #Pavel Stehule is right:
Don't try to pass parameters to triggers, ever!
Second, you just have to get the inserted id into a variable.
CREATE FUNCTION create_user_with_role(first_name text, last_name text, new_role_id integer)
RETURNS VOID AS $$
DECLARE
new_user_id integer;
BEGIN
INSERT INTO users (fname, lname) VALUES (first_name, last_name)
RETURNING id INTO new_user_id;
INSERT INTO users_roles (user_id, role_id)
VALUES (new_user_id, new_role_id);
END;$$ LANGUAGE plpgsql;
Obviously, this is completely inefficient if you want to insert multiple rows but that's another question ;)
When you need to pass any parameter to trigger, then there is clean, so your design is wrong. Usually triggers should to have check or audit functionality. Not more. You can use a function, and call function directly from your application. Don't try to pass parameters to triggers, ever! Another bad sign are artificial columns in table used just only for trigger parametrization. This is pretty bad design!
We're in process of converting over from SQL Server to Postgres. I have a scenario that I am trying to accommodate. It involves inserting records from one table into another, WITHOUT listing out all of the columns. I realize this is not recommended practice, but let's set that aside for now.
drop table if exists pk_test_table;
create table public.pk_test_table
(
recordid SERIAL PRIMARY KEY NOT NULL,
name text
);
--example 1: works and will insert a record with an id of 1
insert into pk_test_table values(default,'puppies');
--example 2: fails
insert into pk_test_table
select first_name from person_test;
Error I receive in the second example:
column "recordid" is of type integer but expression is of type
character varying Hint: You will need to rewrite or cast the
expression.
The default keyword will tell the database to grab the next value.
Is there any way to utilize this keyword in the second example? Or some way to tell the database to ignore auto-incremented columns and just them be populated like normal?
I would prefer to not use a subquery to grab the next "id".
This functionality works in SQL Server and hence the question.
Thanks in advance for your help!
If you can't list column names, you should instead use the DEFAULT keyword, as you've done in the simple insert example. This won't work with a in insert into ... select ....
For that, you need to invoke nextval. A subquery is not required, just:
insert into pk_test_table
select nextval('pk_test_table_id_seq'), first_name from person_test;
You do need to know the sequence name. You could get that from information_schema based on the table name and inferring its primary key, using a function that takes just the table name as an argument. It'd be ugly, but it'd work. I don't think there's any way around needing to know the table name.
You're inserting value into the first column, but you need to add a value in the second position.
Therefore you can use INSERT INTO table(field) VALUES(value) syntax.
Since you need to fetch values from another table, you have to remove VALUES and put the subquery there.
insert into pk_test_table(name)
select first_name from person_test;
I hope it helps
I do it this way via a separate function- though I think I'm getting around the issue via the table level having the DEFAULT settings on a per field basis.
create table public.pk_test_table
(
recordid integer NOT NULL DEFAULT nextval('pk_test_table_id_seq'),
name text,
field3 integer NOT NULL DEFAULT 64,
null_field_if_not_set integer,
CONSTRAINT pk_test_table_pkey PRIMARY KEY ("recordid")
);
With function:
CREATE OR REPLACE FUNCTION func_pk_test_table() RETURNS void AS
$BODY$
INSERT INTO pk_test_table (name)
SELECT first_name FROM person_test;
$BODY$
LANGUAGE sql VOLATILE;
Then just execute the function via a SELECT FROM func_pk_test_table();
Notice it hasn't had to specify all the fields- as long as constraints allow it.
In PostgreSQL 9.1, I need to assign another field in a table with the same value of the ID column which is serial.
For now I'm adding a RETURNING part to INSERT command and use a successive UPDATE command to update the record in the same transaction.
I'd really like to perform this operation in the same transaction and preferably same SQL command (without the need to resort to after insert triggers).
My question is inside the before insert trigger on the same table, is the NEW variable which is supposed to contain the record which is about to be inserted, already initialized with the return value of nextval('seq_table') for the id field or not?
Can I assign this value to another field in the same trigger function? is this valid?
NEW.custom_field := NEW.id;
I use DB2 Express-C.
I have ON INSERT trigger on a table, where I insert the new row into another table.
Is there a way not to insert the new row into the table on which the trigger is defined?
Any help is appreciated, thank you
Take a look at create trigger and the INSTEAD OF option:
Specifies that the associated triggered action replaces the action
against the subject view. Only one INSTEAD OF trigger is allowed for
each kind of operation on a given subject view (SQLSTATE 428FP).
Typically something like this can be done by evaluating whether a special register (e.g., CURRENT USER) has a particular value.
create trigger trigger1
after insert on schema.table
referencing new as n
for each row
when (CURRENT USER <> 'NAMSARAY')
insert into schema.tablecopy values (n.c1, n.c2, ...);
If you are on DB2 9.7 or later, you could also consider defining a variable and using that variable as a control of whether or not the trigger will perform its action.
create variable schema.var1 smallint default 0;
Then you can check the value of this variable in the trigger. Unless an application has explicitly set the variable to a predetermined value (-9999 in the example below), the trigger will fire:
create trigger trigger2
after insert on schema.table
referencing new as n
for each row
when (schema.var1 <> -9999)
insert into schema.tablecopy values (n.c1, n.c2, ...);