Return the id of the just added row - tsql

In a similar vein to my previous question I again ask the SO guys for your collective wisdom and help.
In a stored procedure and after passing some checks I need to insert a new row and return the newly created id for it. The check if a row exists works so it is the bit after that which I am undecided upon.
The table has two important columns: The LocationID and the CaseID. The CaseID is autoincrementing, so when you add insert a new locationid it will automatically rachet up.
I currently have this:
-- previous checks for existance of CaseID
IF #CaseID IS NULL
BEGIN
INSERT INTO
Cases(LocationID)
VALUES
(#LocationID)
-- what now?
END
I was thinking of performing a #CaseID = (SELECT blah) statement immeadiately after but I was wondering if there is a better way?
Is there a better way? How would you do this?

SELECT #CaseID = SCOPE_IDENTITY()
In fact, you can just do (if that's the end of the stored proc.):
SELECT SCOPE_IDENTITY()
(The OUTPUT clause is only available in SQL Server 2005 onwards...)
Ref: SCOPE_IDENTITY

scope_identity()

SELECT SCOPE_IDENTITY()

As others mentioned, SCOPE_IDENTITY() is the way to go, though some ORM tools provide this functionality as well.
The only thing you need to remember is SCOPE_IDENTITY() will return the last identity key value generated during the current session only. This is useful in filtering out new keys which may have been created by other clients simultaneously. SELECT ##IDENTITY will return the last key generated by any client/session.

You need to use the OUTPUT clause
http://blog.jemm.net/articles/databases/how-to-using-sql-server-2005s-output-to-return-generated-identity/
...which, as pointed out, is only available in sqlserver 2005. Plz disregard.

Related

Is there a way to generate some set of rows exactly once on demand in Postgres?

The basic problem is that we are managing a significant amount of generated rows, and it is mission critical that this data is generated exactly once and only if necessary. Suppose you have a data relation:
CREATE TABLE sometable (
id SERIAL,
refID INTEGER,
...
);
Now, in some PL/PGSQL function we have:
...
-- Advisory locks didn't help here? :(
IF FALSE = SELECT EXISTS( SELECT 1 FROM sometable WHERE refID = dataID) THEN
-- Generate fixed number of new rows in sometable that reference dataID.
END IF;
...
In short, the rows that should not be generated more than once some times are. As noted, advisory locks of the form PERFORM pg_advisory_lock(dataID) sadly did not help prevent this. Is there any hope?
EDIT: Forgot to mention that I ran into the duplicate data issue when testing with pgbench.
EDIT 2: Incorrect code fix, clarify issue.
Perhaps the simplest solution is just to have a separate processed_ids table with a unique constraint on the id in question. Your function can try to insert to that table and if there is an exception then that ID is already processed.

In a stored procedure (SQL Server 2008 R2 SP2) is it possible to return a NewSequentialID() without a temp table variable?

In a stored procedure (using SQL Server 2008 R2 SP2) is it possible to return a NewSequentialID() without a temp table variable?
I can successfully obtain the NewSequentialID() by using a temp table:
Getting Value of NEWSEQUENTIALID() on Insert
Perhaps I’m old school, but I try to refrain from using temp tables unless absolutely necessary… though this might be a case where it is absolutely necessary…
IF I try:
DECLARE #NewSequentialID UNIQUEIDENTIFIER;
SET #NewSequentialID = NEWID()
… it works as expected.
IF I try:
DECLARE #NewSequentialID UNIQUEIDENTIFIER;
SET #NewSequentialID = NEWSEQUENTIALID()
… I receive the following error:
The newsequentialid() built-in function can only be used in a DEFAULT
expression for a column of type ‘uniqueidentifier’ in a CREATE TABLE
or ALTER TABLE statement. It cannot be combined with other operators
to form a complex scalar expression.
Is the ONLY solution to use a temp table method?
Does anyone know of a reason why Microsoft implemented a difference between NEWSEQUENTIALID() to work like NEWID()?
Anyone know if there's a chance Microsoft will update NEWSEQUENTIALID() to work like NEWID()?
Geo
UPDATE --
I'm not sure why Microsoft choose to implement the method in this manner, since they state that, "NEWSEQUENTIALID is a wrapper over the Windows UuidCreateSequential function"... but it appears that there is no non-temp-variable table method. (At least as of yet.)Thanks for everyone's comments / answers. [Moderator Note:] I'm not sure what to do with a question when the answer is "not possible". So I'm going to give #marc_s credit for detailing a workaround.
For now - newsequentialid() can only be used as a default constraint on a column. That's what the error message pretty clearly says, too.
So in order to get your sequential GUID's - you must have a table. No other way to do this. And no other way in SQL Server 2012, either.
I have no idea nor any information as to why there's such a difference, and why Microsoft chose to implement it this way....
Update:
OK, so you need to get that value that is being inserted into your table - how about using the OUTPUT clause?
Something like:
DECLARE #NewIDs TABLE (NewSeqID UNIQUEIDENTIFIER)
INSERT INTO dbo.YourTable(list-of-columns)
OUTPUT INSERTED.NewSeqID INTO #NewIDs(NewSeqID)
VALUES (.........)
This way, the output from the INSERT operation - the newly created sequential GUIDs - is being stored into that table variable, and you can use that, return it, slice it - whatever you like!
the official Microsoft saying is:
NEWSEQUENTIALID() can only be used with DEFAULT constraints on table
columns of type uniqueidentifier. For example: CREATE TABLE myTable
(ColumnA uniqueidentifier DEFAULT NEWSEQUENTIALID())
described here
http://msdn.microsoft.com/en-us/library/ms189786.aspx
NewID generates a random number and the other is the next sequential number.

c# ora-02291 error

This is an odd one...
I have two tables tableA and tableB
tableB has a foreign key in tableA.
I have 2 sprocs, one inserts to tableA, the other to tableB.
using odp.net I run the first sproc, inserting a record into tableA. I can then open SQLPlus and select this record
I then run the second sproc, inserting into tableB.
It fails with "ora-02291-integrity-constraint-violated-parent-key-not-found"
I have double, triple, quadruple checked for typos etc... nothing.
To make things even more odd when I do this same operation manually in SQLPlus, with the same sprocs, it works without a problem.
This is killing me 12+ hours looking for something I know has to be simple.
Here are the sprocs.
SPROCA
CREATE OR REPLACE PROCEDURE genData_TestTrackerSegment
(
INTX_ID IN IntxSegment.IntxID%TYPE,
siteid IN INT
)
AS
BEGIN
INSERT INTO INTXSEGMENT(INTXID,INTXTYPEID,VERSION,ISPRIVATE,
SEGMENTTYPE,STARTDATETIME,INTXDIRECTION,SITEID)
VALUES(INTX_ID,1,1,0,1,SYSDATE,1,siteid);
COMMIT;
END;
SPROCB
CREATE OR REPLACE PROCEDURE genData_TestTrackerPart
(
INTX_ID IN IntxSegment.IntxID%TYPE,
INTX_PART_ID IN INTX_PARTICIPANT.INTX_PART_ID%TYPE,
INDIVID IN INDIVIDUAL.INDIVID%TYPE,
CALLID IN INTX_PARTICIPANT.CALLIDKEY%TYPE
)AS
BEGIN
INSERT INTO
INTX_PARTICIPANT(INTXID,INTX_PART_ID,INDIVID,ROLE,
CALLIDKEY,RECORDED,VERSION,STARTDATETIME)
VALUES(INTX_ID,INTX_PART_ID,INDIVID,1,CALLID,1,1,SYSDATE);
COMMIT;
END;
Yeah I am more than certain - it is without a shadow of a doubt that FKEY.
That being said I fixed this..... This is sooooooo stupid by the way.
I was under the (mistaken) assumption that 'named parameters' in ODP.NET meant I did not have to add these parameters in the same order they are referenced in the stored procedure. Long story short - after I re-wrote this about 4 times I modified the order of the parameters and it is now fixed. –
For me, ORA-02291 error means that one of the FK used is not a valid pk or not an existing pk from the other table.
Just Make sure that each FK inserted in your TABLE is a valid one.

Write Insert Query in SQLite3 in iPhone

Hi need insert data in table if the record is not already exits
Ex:
IF NOT EXISTS (SELECT Id FROM table WHERE id=_Id) THEN
INSERT INTO tbale(.....)
This can be easily done using stored procedure in MySql. But I want to d same thing in SQLite by writing a single query statement.
Pleas help
INSERT INTO CategoryMaster (CategoryID, CategoryText) SELECT %d,'%#' WHERE NOT EXISTS (SELECT 1 FROM CategoryMaster WHERE CategoryID= %d)
Its working for me :)
SQlite doesn't have stored procedudes that you need to do logic like this. But you can always extend sqlite with simple C-functions. Or you could simply code this logic in whatever language you are writing your program in. I don't think the performance hit is that great. Did your profiling show that this is a critical path that needs to be optimized?
Put a unique index on the id column (or make it the primary key) then use:
REPLACE INTO table(.....)
see:
http://www.sqlite.org/lang_insert.html or http://www.sqlite.org/lang_replace.html
I would do this by running a first query to see if the record exists then decide whether to run an insert or update. I don't think SQLite has a fully featured query language to support the desired shorter approach.

how to emulate "insert ignore" and "on duplicate key update" (sql merge) with postgresql?

Some SQL servers have a feature where INSERT is skipped if it would violate a primary/unique key constraint. For instance, MySQL has INSERT IGNORE.
What's the best way to emulate INSERT IGNORE and ON DUPLICATE KEY UPDATE with PostgreSQL?
With PostgreSQL 9.5, this is now native functionality (like MySQL has had for several years):
INSERT ... ON CONFLICT DO NOTHING/UPDATE ("UPSERT")
9.5 brings support for "UPSERT" operations.
INSERT is extended to accept an ON CONFLICT DO UPDATE/IGNORE clause. This clause specifies an alternative action to take in the event of a would-be duplicate violation.
...
Further example of new syntax:
INSERT INTO user_logins (username, logins)
VALUES ('Naomi',1),('James',1)
ON CONFLICT (username)
DO UPDATE SET logins = user_logins.logins + EXCLUDED.logins;
Edit: in case you missed warren's answer, PG9.5 now has this natively; time to upgrade!
Building on Bill Karwin's answer, to spell out what a rule based approach would look like (transferring from another schema in the same DB, and with a multi-column primary key):
CREATE RULE "my_table_on_duplicate_ignore" AS ON INSERT TO "my_table"
WHERE EXISTS(SELECT 1 FROM my_table
WHERE (pk_col_1, pk_col_2)=(NEW.pk_col_1, NEW.pk_col_2))
DO INSTEAD NOTHING;
INSERT INTO my_table SELECT * FROM another_schema.my_table WHERE some_cond;
DROP RULE "my_table_on_duplicate_ignore" ON "my_table";
Note: The rule applies to all INSERT operations until the rule is dropped, so not quite ad hoc.
For those of you that have Postgres 9.5 or higher, the new ON CONFLICT DO NOTHING syntax should work:
INSERT INTO target_table (field_one, field_two, field_three )
SELECT field_one, field_two, field_three
FROM source_table
ON CONFLICT (field_one) DO NOTHING;
For those of us who have an earlier version, this right join will work instead:
INSERT INTO target_table (field_one, field_two, field_three )
SELECT source_table.field_one, source_table.field_two, source_table.field_three
FROM source_table
LEFT JOIN target_table ON source_table.field_one = target_table.field_one
WHERE target_table.field_one IS NULL;
Try to do an UPDATE. If it doesn't modify any row that means it didn't exist, so do an insert. Obviously, you do this inside a transaction.
You can of course wrap this in a function if you don't want to put the extra code on the client side. You also need a loop for the very rare race condition in that thinking.
There's an example of this in the documentation: http://www.postgresql.org/docs/9.3/static/plpgsql-control-structures.html, example 40-2 right at the bottom.
That's usually the easiest way. You can do some magic with rules, but it's likely going to be a lot messier. I'd recommend the wrap-in-function approach over that any day.
This works for single row, or few row, values. If you're dealing with large amounts of rows for example from a subquery, you're best of splitting it into two queries, one for INSERT and one for UPDATE (as an appropriate join/subselect of course - no need to write your main filter twice)
To get the insert ignore logic you can do something like below. I found simply inserting from a select statement of literal values worked best, then you can mask out the duplicate keys with a NOT EXISTS clause. To get the update on duplicate logic I suspect a pl/pgsql loop would be necessary.
INSERT INTO manager.vin_manufacturer
(SELECT * FROM( VALUES
('935',' Citroën Brazil','Citroën'),
('ABC', 'Toyota', 'Toyota'),
('ZOM',' OM','OM')
) as tmp (vin_manufacturer_id, manufacturer_desc, make_desc)
WHERE NOT EXISTS (
--ignore anything that has already been inserted
SELECT 1 FROM manager.vin_manufacturer m where m.vin_manufacturer_id = tmp.vin_manufacturer_id)
)
INSERT INTO mytable(col1,col2)
SELECT 'val1','val2'
WHERE NOT EXISTS (SELECT 1 FROM mytable WHERE col1='val1')
As #hanmari mentioned in his comment. when inserting into a postgres tables, the on conflict (..) do nothing is the best code to use for not inserting duplicate data.:
query = "INSERT INTO db_table_name(column_name)
VALUES(%s) ON CONFLICT (column_name) DO NOTHING;"
The ON CONFLICT line of code will allow the insert statement to still insert rows of data. The query and values code is an example of inserted date from a Excel into a postgres db table.
I have constraints added to a postgres table I use to make sure the ID field is unique. Instead of running a delete on rows of data that is the same, I add a line of sql code that renumbers the ID column starting at 1.
Example:
q = 'ALTER id_column serial RESTART WITH 1'
If my data has an ID field, I do not use this as the primary ID/serial ID, I create a ID column and I set it to serial.
I hope this information is helpful to everyone.
*I have no college degree in software development/coding. Everything I know in coding, I study on my own.
Looks like PostgreSQL supports a schema object called a rule.
http://www.postgresql.org/docs/current/static/rules-update.html
You could create a rule ON INSERT for a given table, making it do NOTHING if a row exists with the given primary key value, or else making it do an UPDATE instead of the INSERT if a row exists with the given primary key value.
I haven't tried this myself, so I can't speak from experience or offer an example.
This solution avoids using rules:
BEGIN
INSERT INTO tableA (unique_column,c2,c3) VALUES (1,2,3);
EXCEPTION
WHEN unique_violation THEN
UPDATE tableA SET c2 = 2, c3 = 3 WHERE unique_column = 1;
END;
but it has a performance drawback (see PostgreSQL.org):
A block containing an EXCEPTION clause is significantly more expensive
to enter and exit than a block without one. Therefore, don't use
EXCEPTION without need.
On bulk, you can always delete the row before the insert. A deletion of a row that doesn't exist doesn't cause an error, so its safely skipped.
For data import scripts, to replace "IF NOT EXISTS", in a way, there's a slightly awkward formulation that nevertheless works:
DO
$do$
BEGIN
PERFORM id
FROM whatever_table;
IF NOT FOUND THEN
-- INSERT stuff
END IF;
END
$do$;