Doing a for-each record in a user defined table type in Stored Procedure - sql

:)
I have this defined type:
CREATE TYPE dbo.MyType
AS TABLE
(
name varchar(255),
value varchar(255)
);
Having this stored procedure:
CREATE PROCEDURE MyProcedure #docName varchar(255), #docPath varchar(255), #values AS [dbo].MyType Readonly
AS
declare #ID table (ID int)
INSERT INTO MyTable output inserted.fileID into #ID values (#docName,#docPath)
-- insert loop here
GO;
And the following "one to many" table
CREATE TABLE TableN (
fileID int PRIMARY KEY,
name varchar(255),
value varchar(255)
)
How can I, where it is noted in the above code, make a loop in order to for each record in the MyType table, to insert it into TableN, together with the fileID from the insert?
Thanks!

There's no need for a loop (you need to stop thinking programmatically in SQL and think in datasets). Just do an INSERT:
INSERT INTO TableN (FileID,[name],[value])
SELECT ID.ID,
V.[Name],
V.[value]
FROM #values v
CROSS JOIN #ID ID;

Related

How to return NULL for Identity when no INSERT is performed

I have two tables
CREATE TABLE Temp_1
(
ID Int IDENTITY(1,1),
Name Varchar(500)
)
CREATE TABLE Temp_2
(
ID Int IDENTITY(1,1),
Name Varchar(500)
)
INSERT INTO Temp_1
SELECT 'CC'
INSERT INTO Temp_2
SELECT Name
FROM Temp_1
WHERE 2 = 1
There is no insertion into the table Temp_2.So my expected output for the SCOPE_IDENTITY () for the table Temp_2 is NULL.
How can i get the Identity Value of the Temp_2 as null?
If we use the SCOPE_IDENTITY() OR ##IDENTITY, the identity value we are getting is only of the table Temp_1. We need to get the identity value of table Temp_2 which is "null" as there is no insertion in the table Temp_2 .
Neither. You want to use the output clause:
DECLARE #ids TABLE (id INT);
INSERT INTO Temp_1
OUTPUT inserted.id INTO #ids
SELECT 'CC' ;
This is session-safe, statement-safe, multi-threaded safe. And it allows you to handle multiple row inserts. And it allows you to return additional columns.
There is no reason to use any other method.

Handling bulk insert on a table with multiple input sources in SQL

I am performing bulk insert on a table in sql server 2012, at the same time i am picking the last inserted row with max() function and inserting it into another table , how to perform this when my table is getting data from multiple sources because while performing insertion into secondary table there is time delay while insertions are still happening in primary table so next time max() will pick up last updated row and i will loose some rows which are not max() but still inserted into primary table meanwhile.
create table dbo.emp
(
id int primary key identity(1,1),
emp_id int,
name varchar(255),
address varchar(255)
)
create table dbo.empx
(
id int primary key,
emp_id int foreign key references dbo.emp(id),
)
declare #temp int ;
set #temp=1;
while #temp<1000
begin
insert into dbo.emp(emp_id,name,address)values (100+#temp,'Ename'+LTRIM(STR(#temp)),'123 Sample Address'+LTRIM(STR(#temp)));
set #temp=#temp+1;
insert into dbo.empx select max(dbo.emp.id),max(dbo.emp.emp_id) from dbo.emp
end
Use OUTPUT Clause...
CREATE TABLE #empx
(Id INT ,emp_id VARCHAR(50))
DECLARE #temp INT ;
SET #temp=1;
WHILE #temp<1000
BEGIN
INSERT INTO dbo.emp(emp_id,name,address)
OUTPUT INSERTED.Id,INSERTED.emp_id INTO #empx(Id,emp_id)
VALUES (100+#temp,'Ename'+LTRIM(STR(#temp)),'123 Sample Address'+LTRIM(STR(#temp)));
SET #temp=#temp+1;
END
INSERT INTO dbo.empx(Id,emp_id)
SELECT Id,emp_id FROM #empx
Or Use a trigger
CREATE TRIGGER EmpLog
ON dbo.emp
AFTER Insert
AS
BEGIN
SET NOCOUNT ON;
Insert into dbo.empx (id,emp_id) Select id,emp_id from inserted;
END
GO

SQL Insert With Unique Constraint using Stored Procedure

This is a generic question with a specific example.
I have a table with three fields (genreID (PK IDENTITY), genre, and subGenre). The table has a unique constraint on (genre, subGenre) combination.
I am wondering how I could go about modifying the stored procedure to insert if it DOES NOT exist in the table, otherwise return the genreID of the existing genre if it DOES exist.
CREATE PROCEDURE spInsertGenre
#genreID int OUTPUT,
#genre varchar(100),
#subGenre varchar(100)= NULL
AS
BEGIN
INSERT INTO Genre
(
genre,
subGenre
)
Values (
#genre,
#subGenre
)
SELECT #genreID = SCOPE_IDENTITY()
END
GO
You can try to select the row that would be inserted by your SP before you do the insert:
CREATE PROCEDURE spInsertGenre
#genreID int OUTPUT,
#genre varchar(100),
#subGenre varchar(100)= NULL
AS
BEGIN
-- if the row to be inserted already exists, put the genreID into the #genreID output parameter
SELECT #genreID = genreID
FROM Genre
WHERE genre = #genre
AND subGenre = #subGenre
IF #genreID IS NULL -- if the genreID was not found, do an insert and select the new genreID to the #genreID output parameter
BEGIN
INSERT INTO Genre
(
genre,
subGenre
)
Values (
#genre,
#subGenre
)
SELECT #genreID = SCOPE_IDENTITY()
END
END
GO

how to get id of newly inserted rows using openxml?

I have a XML block which I want to insert into database. database contains 3 tables namely itemMapping, links and category. Links table will have only link from XML, category table will have category from XML.
<item>
<link>http://google.com</link>
<category>search engine</category>
<category>android</category>
<category>gmail</category>
</item>
Here come my confusion, 'itemMaping' table contains following columns :
ID, LinkID, CategoryID
In itemMapping table I have to insert linkID and categoryID of newly inserted rows. So according to sample XML itemMapping table will have 3 records for each category, but to insert record in this table i will need linkID and categoryID from above. How I can achieve this? I want to do this in single SP if possible.
Hi Consider the following tables:
Country Table
CountryID CountryName LastEditUser
Province table
ProvinceID ProvinceName CountryID LastEditUser
Consider CountryID and ProvinceID were identity columns.
IN SQL YOU can insert records to these two tables using a single stored procedure take a look at the quick example
CREATE PROCEDURE InsertProvince
(
#ProvinceName VARCHAR(128),
#CountryName VARCHAR(128),
#LastEditUser VARCHAR(128)
)
AS
DECLARE #CountryID INT
INSERT INTO Country
(CountryName, LastEditUser)
VALUES
(#CountryName, #LastEditUser)
#CountryID = SCOPE_IDENTITY();
INSERT INTO Province
(ProvinceName, CountryID, LastEditUser)
VALUES
(#ProvinceName, #CountryID, #LastEditUser)
END
SQL Server has a function called scope_identity, it returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
Insert into Links and capture the LinkID with scope_identity() to a variable. Insert into Category and capture the generated ID's in a table variable. Use that table variable as source for the insert to ItemMapping.
Assuming your tables look like this.
create table Category
(
CategoryID int identity primary key,
Name varchar(50)
)
create table Links
(
LinkID int primary key identity,
Link varchar(50)
)
create table ItemMapping
(
LinkID int references Links(LinkID),
CategoryID int references Category(CategoryID),
primary key(LinkID, CategoryID)
)
You can do like this using an XML variable #XML.
declare #IDs table(ID int)
declare #LinkID int
insert into Links(Link)
select T.X.value('.', 'nvarchar(50)')
from #XML.nodes('item/link') as T(X)
set #LinkID = scope_identity()
insert into Category(Name)
output inserted.CategoryID into #IDs
select T.X.value('.', 'nvarchar(50)')
from #XML.nodes('item/category') as T(X)
insert into ItemMapping(LinkID, CategoryID)
select #LinkID, I.ID
from #IDs as I
SE-Data

insert data into several tables

Let us say I have a table (everything is very much simplified):
create table OriginalData (
ItemName NVARCHAR(255) not null
)
And I would like to insert its data (set based!) into two tables which model inheritance
create table Statements (
Id int IDENTITY NOT NULL,
ProposalDateTime DATETIME null
)
create table Items (
StatementFk INT not null,
ItemName NVARCHAR(255) null,
primary key (StatementFk)
)
Statements is the parent table and Items is the child table. I have no problem doing this with one row which involves the use of IDENT_CURRENT but I have no idea how to do this set based (i.e. enter several rows into both tables).
Thanks.
Best wishes,
Christian
Another possible method that would prevent the use of cursors, which is generally not a best practice for SQL, is listed below... It uses the OUTPUT clause to capture the insert results from the one table to be used in the insert to the second table.
Note this example makes one assumption in the fact that I moved your IDENTITY column to the Items table. I believe that would be acceptable, atleast based on your original table layout, since the primary key of that table is the StatementFK column.
Note this example code was tested via SQL 2005...
IF OBJECT_ID('tempdb..#OriginalData') IS NOT NULL
DROP TABLE #OriginalData
IF OBJECT_ID('tempdb..#Statements') IS NOT NULL
DROP TABLE #Statements
IF OBJECT_ID('tempdb..#Items') IS NOT NULL
DROP TABLE #Items
create table #OriginalData
( ItemName NVARCHAR(255) not null )
create table #Statements
( Id int NOT NULL,
ProposalDateTime DATETIME null )
create table #Items
( StatementFk INT IDENTITY not null,
ItemName NVARCHAR(255) null,
primary key (StatementFk) )
INSERT INTO #OriginalData
( ItemName )
SELECT 'Shirt'
UNION ALL SELECT 'Pants'
UNION ALL SELECT 'Socks'
UNION ALL SELECT 'Shoes'
UNION ALL SELECT 'Hat'
DECLARE #myTableVar table
( StatementFk int,
ItemName nvarchar(255) )
INSERT INTO #Items
( ItemName )
OUTPUT INSERTED.StatementFk, INSERTED.ItemName
INTO #myTableVar
SELECT ItemName
FROM #OriginalData
INSERT INTO #Statements
( ID, ProposalDateTime )
SELECT
StatementFK, getdate()
FROM #myTableVar
You will need to write an ETL process to do this. You may want to look into SSIS.
This also can be done with t-sql and possibly temp tables. You may need to store unique key from OriginalTable in Statements table and then when you are inserting Items - join OriginalTable with Statements on that unique key to get the ID.
I don't think you could do it in one chunk but you could certainly do it with a cursor loop
DECLARE #bla char(10)
DECLARE #ID int
DECLARE c1 CURSOR
FOR
SELECT bla
FROM OriginalData
OPEN c1
FETCH NEXT FROM c1
INTO #bla
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO Statements(ProposalDateTime) VALUES('SomeDate')
SET #ID = SCOPE_IDENTITY()
INSERT INTO Items(StateMentFK,ItemNAme) VALUES(#ID,#bla)
FETCH NEXT FROM c1
INTO #bla
END
CLOSE c1
DEALLOCATE c1