SQL insert ID from IDENTITY ID of the row being inserted - sql

I would like to know, if there is a direct way to insert ID (generated at ID column with IDENTITY(1,1)) to another columns.
In another words, I am looking for SCOPE_IDENTITY() I could get at the time of inserting, not after the INSERT is commited.
I have a table, where there is a column with secondary ID (SID), which references rows from the same table and in some special cases it references itself.
The only way I know to do that is to do the INSERT and consequently UPDATE SID in those cases. Simplified example:
DECLARE #ID INT
INSERT INTO Table (SID) VALUES (NULL);
SELECT #ID = SCOPE_IDENTITY();
UPDATE Table SET SID = ID WHERE ID = #ID;
There are some glitches, i.e. due to the fact that the row may or may not reference itself, etc.

You can do this with an AFTER INSERT trigger. In case of self-reference, leave the column NULL and have the trigger set the column equal to the IDENTITY column.
In pseudo:
Join the table with inserted, filter where SID is NULL
For those rows, update the table and set SID = ID
If it is not possible to use the NULL value, in cases where it should be possible to have no reference at all, you can use another stub value. E.g. -1 if the IDs will always be positive. In that case, apply the above way of working and substitute NULL with -1.

Related

SQL Server trigger can't insert

I beginning to learn how to write trigger with this basic database.
I'm also making my very 1st database.
Schema
Team:
TeamID int PK (TeamID int IDENTITY(0,1) CONSTRAINT TeamID_PK PRIMARY KEY)
TeamName nvarchar(100)
History:
HistoryID int PK (HistoryID int IDENTITY(0,1) CONSTRAINT HistoryID_PK PRIMARY KEY)
TeamID int FK REF Team(TeamID)
WinCount int
LoseCount int
My trigger: when a new team is inserted, it should insert a new history row with that team id
CREATE TRIGGER after_insert_Player
ON Team
FOR INSERT
AS
BEGIN
INSERT INTO History (TeamID, WinCount, LoseCount)
SELECT DISTINCT i.TeamID
FROM Inserted i
LEFT JOIN History h ON h.TeamID = i.TeamID
AND h.WinCount = 0 AND h.LoseCount = 0
END
Executed it returns
The select list for the INSERT statement contains fewer items than the insert list. The number of SELECT values must match the number of INSERT columns.
Please help thank. I'm using SQL Server
The error text is the best guide, it is so clear ..
You try inserting one value from i.TeamID into three columns (TeamID,WinCount,LoseCount)
consider these WinCount and LoseCount while inserting.
Note: I Think the structure of History table need to revisit, you should select WinCount and LoseCount as Expressions not as actual columns.
When you specify insert columns, you say which columns you will be filling. But in your case, right after insert you select only one column (team id).
You either have to modify the insert to contain only one column, or select, to retrieve 3 fields as in insert.
If you mention the columns where values have to be inserted(Using INSERT-SELECT).
The SELECT Statement has to contain the same number of columns that have been specified to be inserted. Also, ensure they are of the same data type.(You might face some issues otherwise)

Increment number on insert into?

Here's my dilemma,
I have the following columns:
ID_C int and NAME varchar
Problem is that ID_C is not set to auto-increment because it's linked to another table with the information on that particular ID_C number. So it cannot auto-increment without having the number in there first, that's why it's not set for auto-increment.
How can I do
INSERT INTO Table (ID_C, name)
VALUES (<<This place should query for the last item and increment on the result>>,'Tom B. Erichsen')
INSERT INTO [Table](ID_C, name) SELECT MAX(ID_C)+1, 'stack' FROM user_table
you can use dml trigger also.(after insert)
refernce
http://www.mssqltips.com/sqlservertip/2342/understanding-sql-server-inserted-and-deleted-tables-for-dml-triggers/

sql: insert object spread over multiple tables

There are already posts, for example this one, which state that "naive" inheritance in SQL, namely using one table per class level, is a common thing. Example
create table parent
( id integer primary key
, more-parent-attributes
);
create table child
( id integer primary key references parent(id) on delete cascade
, more-child-attributes
);
My question is only how to insert a child in an idiomatic ANSI SQL way
into the table. The foreign key constraint makes the requirement that we first
insert a new row into parent and then a new row into child, using the id
of the parent row. I don't know how to do this (get this id) safely and portably, and
using only one request.
Hint: I'm rather a beginner and don't know imperative SQL programming--just in
case there is an obvious imperative solution.
You must execute two insert.
The first insert add row in parent table, the second insert add row in the child table.
Two insert operations can be grouped in the same transaction.
To get the correct inserted id in the parent table you must get a select id from parent.
Show below:
Step 1:
INSERT INTO parent (id, more att) values (your ID, other values)
Pay attention about ID value, you can use newid() (Sql server) uuid() (mySql) or autoincremental integer field
Step 2:
You retrieve your key querying your parent table with a functional key.
SELECT id FROM parent where functional_key satisfacted
For example, if I store in my parent table a list of employes, a functional key can be register number.
So your query becomes:
SELECT id FROM parent WHERE register_no = 'YOUR_REGISTER_NUMBER'
Step 3:
INSERT INTO child (id, fk_parent, other fields) values(id, fk_parent, other fields)
The fk_parent field must be valued with the result of Step 2.
In this step you can:
value fk_parent with a variable or you can use a subquery (step 2) in your insert statement.
I ended up doing something similar. You need to have some identifying piece of data that you can insert into the Parent in order to get the Id. If you're using this in some kind of application then you can use a GUID. In my application I used a concatenation of source columns that I knew would produce a unique value.
CREATE TABLE Parent
(
Id INT IDENTITY NOT NULL PRIMARY KEY
,SourceId VARCHAR(50) NOT NULL
);
CREATE TABLE Child
(
ParentId INT NOT NULL REFERENCES Parent (Id)
,Data VARCHAR(20)
);
-- Some procedure inserts the unique value
INSERT INTO Parent (SourceId) VALUES ('UNIQUE VALUE');
-- Another procedure inserts data using the unique value
DECLARE #Id INT;
SELECT #Id = Id FROM Parent WHERE SourceId = 'UNIQUE VALUE';
INSERT INTO Child (ParentId, Data) VALUES (#Id, 'Some Data');
Scope_Identity() is what you looking for:
DECLARE #Id INT
INSERT INTO parent (more-parent-attributes) values (.....)
SET #Id = Scope_Identity()
INSERT INTO child (parent(id), more-child-attributes) SELECT #Id, ....more-child-attributes
Scope_Identity() returns identity column in the same scope. It means that Parent key should be Identity column:
id int IDENTITY(1,1)PRIMARY KEY
and I think this is the case as if you were deciding what is the Parent key id, you would use the same for child insert.

Inserting row with foreign key relation in same transaction as primary row

I have a 2 tables where one has a foreign key relation to the other
CREATE TABLE foo (
id INT NOT NULL PRIMARY KEY IDENTITY,
value VARCHAR(50) DEFAULT NULL,
);
CREATE TABLE bar (
id INT NOT NULL PRIMARY KEY IDENTITY,
foo_key INT NOT NULL
value VARCHAR(50) DEFAULT NULL,
);
I'm using parameterized ADO.NET ExecuteReader to Insert new rows. My pickle is, if I want to insert 2 rows in different tables in the same transaction, i.e. before commit, I cannot insert rows in bar since I don't know the value that has been given foo.id yet. How would you go about doing that? i.e. How do I make sure that bar.foo_key get assigned the right value? Trying to select on it brings nothing, since I guess it is not actually there yet. Should I use a stored procedure to try and generate the key on the fly, or maybe there is an internal variable that can be used. Or is there a way to have the insert return the new id? Do I need a foreign key declaration, though I'm not sure that would be useful since again I still don't know what id to use?
The reason why I want to do it in one go, is due to error handling, I want to be able to roll everything back in case of an error.
You can use scope_identity() to retrieve the newly generated identity:
begin tran;
insert Foo (value) values ('6*7');
declare #fk int = scope_identity();
insert bar (foo_key, value) values (#fk, '42');
commit tran;
Per HLGEM's comment, to return the value of the newly generated identity to the client, you can use output:
insert Foo (value) output inserted.ID values ('6*7');
Note that for a transaction to span two sessions, you need a distributed transaction, which is very expensive.
I figured out I can return scope_identity() on the insert
INSERT INTO [foo] ([value]) VALUES (#0) SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];

Update value on insert into table in SQL Server

I am working with SQL Server - on inserting into a table, I have a unique constraint on a table column id. There is a possibility that when inserting, the value going into the id column is 0. This will cause an error.
Is it possible to update this id to another value during the insert if the id value is 0? This is to prevent the error and to give it a valid value.
Possibly a trigger?
A trigger is one way, but you may want to use a filtered index (CREATE UNIQUE INDEX, not as a table constraint) to ignore zero value. This way, you don't have to worry about what value to put there
Alternatively, if you want to populate it from another column, you can have a computed column with a unique constraint.
ALTER TABLE whatever
ADD ComputedUniqueCol = CASE WHEN Id = 0 THEN OtherCol ELSE Id END
If that's your primary key you can specify it as IDENTITY. Then it should generate a value for itself based on seed and increment (the default is seed=1 and default=1) so you don't have to worry about it.
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY,
...
)
create an "instead of" trigger and check for the value on the ID.
CREATE trigger checkID
on YOUR_TABLE
instead of insert
as
begin
declare #id int
select #id=id from inserted
if (#id==0) begin
--DO YOUR LOGIC HERE AND THEN INSERT
end else begin
insert into DESTINATION_TABLE (VALUES)
SELECT VALUES FROM INSERTED
end
end