How to use insert statement in a select and return new PK value to put as a field of select - sql

I have a code about Insert into a table, for example:
Insert Into MyTable(PropertyName,PropertyID)
values('PropertyName1', (if exists(select 1 from PropertyTable where propertyName='PropertyName1') return null
else
insert into PropertyTable(Name) values('PropertyName1')
return scope_Identity()))
my problem is at there:
insert into PropertyTable(Name) values('PropertyName1')
return scope_Identity()
I need if my row isn't exist in my table, at first insert new value in a table and then return ID for use in above insert.
but i don't know how do it?

I don't know if your code is completely ok, but a alternative solution for the use of scope_identity is output clause.
Try this and tell me if works:
Insert Into MyTable (PropertyName,PropertyID) values('PropertyName1',
(if exists(select 1 from PropertyTable where propertyName='PropertyName1')
return null
else
insert into PropertyTable(Name)
output inserted.nameOfYourIDColumn
values('PropertyName1')));

Related

How to Retrieve the Identity column value in an insert trigger SQL Server

I have two tables that are identical except one has an identity column and the other doesn't. Instead the second table uses the value of the identity column from the first table. I thought I would insert into the second table as a trigger when a record is inserted into the first table. I cannot seem to get syntax right.
Null is being returned from the identity column #EDVisitId.
ALTER TRIGGER [dbo].[trgInserterrEDVisitOriginal] ON [dbo].[errEDVisit]
AFTER INSERT
AS
--Name: Bob Avallone
--Date: 6-15-2017
--
-- The purpose of this trigger is to insert a record into errEDVisitOriginal
-- whenever a new errEDVisit is inserted.
--XXXXXXXXXX
declare #EDVisitId int
declare #SubmissionControlID INT
Select #EDVisitId = EDVisitID from inserted
SELECT #SubmissionControlID = SubmissionControlID from Inserted
Begin
Insert Into errEDVisitOriginal (EDVisitId, SubmissionControlID)
VALUES (#EDVisitId, #SubmissionControlID )
End
Thanks for all the suggestions. I abandoned the idea of a trigger. Instead I simply insert the new records from the first table into the second one. See below.
Insert errEDVisitOriginal(EdVisitId, SubmissionControlID)
Select EdVisitId, SubmissionControlID
from errEDVisit where SubmissionControlID = #SubmissionControlID
you just need scope_identity()
Select #EDVisitId = scope_identity()
You can use SCOPE_IDENTITY to get the last inserted id from the first table put it into a variable then insert into the second table.
https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql
Though the decision to duplicate information intentionally is dubious, you are vastly over-thinking the code. Just:
if exists (select * from inserted)
insert dbo.errEDVisitOriginal (EDVisitId, SubmissionControlID)
select EDVisitId, SubmissionControlID from inserted;

Set value of the column to default for NULL values

I have a table with a column which has default value to 0. However when null is inserted to this table, I want it to set it to default.
As the insert query is generic and used by other databases too, I cannot make any changes to the insert statement.
Can I have constraints or case statement on create table, so that default 0 value is inserted whenever null is passed.
If you can not change an insert statement you have no way other then creating an instead of insert trigger:
CREATE TRIGGER trTableName
ON SchemaName.TableName
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TableName (ColumnA, ColumnB, ...)
SELECT ISNULL(ColumnA, 0), ISNULL(ColumnB, 0), ...
FROM INSERTED
END
You can do an update using a trigger on insert.
CREATE TRIGGER [dbo].[YourTriggerName]
ON [dbo].[YourTable]
AFTER INSERT
AS
BEGIN
UPDATE t SET YourCol = 0
FROM YourTable t
JOIN Inserted i ON t.Id = i.Id
WHERE i.YourCol IS NULL
END
Inserting null is the same as inserting a specific value, and so the default value is bypassed.
To use the default setting the insert statement shouldn't insert anything to this column.
If you can't use Coalesce (value, 0) in the select bit of the into statement, try using it in your select queries to disguise the result.

UPSERT in SQLite

I don't want to use REPLACE INTO because it's basically a DELETE and INSERT and it's complicated to use the data from the old columns.
INSERT OR IGNORE is a bit of a hack because all errors are ignored, so this is not an option.
I've read a blog article which uses the following:
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
IF ##ROWCOUNT=0
INSERT INTO Table1 VALUES (...)
I like this approach really much, but I don't know how I can implement this IF-clause with the ##ROWCOUNT in SQLite, this is what I got:
SELECT CASE (SELECT
CASE
WHEN EXISTS(SELECT 1 FROM t WHERE id=2)
THEN 1
ELSE 0
END)
WHEN 1
UPDATE t set a='pdf' WHERE id=2;
ELSE
INSERT INTO t (a) VALUES ('pdf');
END
the SELECT CASE seems to be the only way to use a CASE-clause in SQLite because everything else throws an syntax error. But it's also not possible to use a UPDATE- or INSERT-statement in the SELECT CASE, so this throws an error.
I've tried the following
UPDATE t set a='pdf' WHERE id=2;
CASE WHEN (changes()=0) THEN
INSERT INTO t (a) VALUES ('pdf');
END
but this doesn't work, because the CASE-clause throws an syntax error.
can someone provide an example using ##ROWCOUNT for an UPSERT in SQLite?
SQLite has no built-in UPSERT-like statement that doesn't delete the old record.
You should check the number of changes in your program, and execute the INSERT conditionally.
However, if you really want to do this in SQL, it's possible; but you have to use the INSERT ... SELECT ... form so that you are able to insert zero records, if needed:
BEGIN;
UPDATE t SET a = 'pdf' WHERE id = 2;
INSERT INTO t(id, a) SELECT 2, 'pdf' WHERE changes() = 0;
COMMIT;
You should use sqlite API in this case and write "IF logic" in your application.
sqlite3_prepare16_v2(stmt1, "UPDATE t SET a=? WHERE id=?");
sqlite3_prepare16_v2(stmt2, "INSERT INTO t(id, a) VALUES(?, ?)");
for(...) // iterate by rows to be updated/inserted
{
//set parameter values for stmt1
sqlite3_step(stmt1);
if( !sqlite3_changes(dbh) )
{
//set parameter values for stmt2
sqlite3_step(stmt2);
}
}

After insert not working

all id columns has auto_increment
In my trigger:
ALTER trigger [dbo].[mytrig]
on [dbo].[requests]
after INSERT, UPDATE
as
begin
declare #MyId1 int
set #MyId1 = (select Id from inserted)
declare #MyId2 int
declare #MyId3 int
if (select column1 from inserted) = 1
begin
insert into [dbo].[contracts] select column1,column2,column3 .... from inserted
set #MyId2 = SCOPE_IDENTITY()
insert into [dbo].[History] select column1,column2,column3 .... from inserted
set #MyId3 = SCOPE_IDENTITY()
insert into [dbo].[contracts_depts](Id_Contract ,column5) select #MyId2,column6 from request_depts where Id_request=#MyId1
insert into [dbo].[History_depts] (Id_InHistory,column5) select #MyId3,column6 from request_depts where Id_request=#MyId1
end
end
#MyId1 returns value only after update but not after insert. Do I have to use scope_identity() or something ?
Your main issue is: you're assuming the triggers is called once per row - that is NOT the case!
The trigger is called once per statement, and if your statement affects multiple rows, the Inserted pseudo table will contain multiple rows - so your statement here
set #MyId1 = (select Id from inserted)
really isn't going to work - it will select one arbitrary row (out of however many there are).
You'll need to rewrite your trigger to take this fact into account! Assume that Inserted contains 100 rows - how do you want to deal with that? What are you trying to achieve? Triggers don't return values - they will record into an audit table, or update other rows, or something like that ....

Getting the identity of the row I just inserted

I've got two tables that are linked with foreign keys. I need to do a few inserts on one table and then use the identity column values are part of my next batch of insert statements. This all has to be done through SQL.
I've been reading about SCOPE_IDENTITY() but all the examples I'm seeing are using ASP/PHP/Whatever to do the substitution in the next batch of inserts, I dont have this option.
Any pointers appreciated.
Use
SCOPE_IDENTITY() - Function
instead of
##IDENTITY Variable -
otherwise you get the result of the last inserted identity - if there is a trigger on the table than does inserting somewhere you get the wrong result back (the value inserted by the trigger and not by your statement). Scope_Identity returns the identity of your statement and that is what you normally want.
IN SQl Server 2008 you can also use the OUTPUT clause.
DECLARE #output TABLE (myid INT)
INSERT mytable (field1, field2)
OUTPUT inserted.myid INTO #output
VALUES ('test', 'test')
SELECT * FROM #output
What makes this espcially valuable is if you use it to insert a bunch of records instead of one you can get all the identities, You can also return any of the other fields you might need.
something like:
DECLARE #output TABLE (myid INT, field1 datetime)
INSERT mytable (field1, field2)
OUTPUT inserted.myid, inserted.field1 INTO #output
Select '20100101', field3 from mytable2
SELECT * FROM #output
You can do the same with SQL or TSQL. Just assign the identify column as soon as you do the insert.
-- Variable to hold new Id
Declare #NewId int
--Insert some values in to create a new ID
Insert Into dbo.MyTable1 (Col1)
Values (#NewValue)
-- Grab the new Id and store it in the variable
Select #NewId = Scope_Identity()
--Insert the new Id in to another table
Insert Into dbo.AnotherTable (Col1)
Values (#NewId)
You can use
SELECT SCOPE_IDENTITY() [Iden]
After the insert statement in the same block. This should work.