Inserting records in loop without any unique columns - sql-server

I have the following table for example which does not have any identity or unique column:
create table tbl_test ( first_name nvarchar(255), last_name nvarchar(255),
[address] nvarchar(255))
Insert tbl_test values ('Andrei','Corovei','str Meteor')
Insert tbl_test values ('Pop','Ionut','str Meteor')
Insert tbl_test values ('Whitehead','John','str Lunii')
Insert tbl_test values ('Grisham','Robert','str Corcoduselor')
Insert tbl_test values ('Eugen','Johnesco','str Prunelor')
I can insert the rows from the above table to a another table using below syntax:
select * into tbl_test_loop from tbl_test
This will insert all records in one shot.
Can I insert in a loop with a batch count of 2 the above results rather than at one shot without creating any Identity or rownumber function?

Declare #loopcount int
Declare #rcount int
Declare #idn int
Declare #iteration int
Declare #strsql varchar(1000)
select #loopcount=2,#idn=1
select #rcount=count(*) from tbl_test
SET #iteration=(#rcount/#loopcount)+(#rcount%#loopcount)
while(#idn<=#iteration)
BEGIN
SET #strsql='INSERT INTO tbl_test_loop select top '+cast(#loopcount as varchar(2))+' * from tbl_test t where not exists(select * from tbl_test_loop l where l.first_name = t.first_name and l.last_name = t.last_name and l.[address] = t.[address])'
exec(#strsql)
select 'inserted '+cast(#loopcount as varchar(2))
SET #idn=#idn+1
END

select tbl_test.* into tbl_test_loop from tbl_test, ( select 1 as loop union select 2) v

Try NTILE, no loop required:
select NTILE(3) OVER( ORDER BY ( SELECT 1 ) ) x, *
into tbl_test_loop
from tbl_test

Related

Insert Into Table with String Insert Or Table Type

I have a table called #Tbl1, Each GROUP is 1 row and I have to extract the number of rows for each to #Tbl_Insert type.
Declare #Tbl1 Table (TableName NVARCHAR(250),ColumnName NVARCHAR(250),DataType NVARCHAR(250),DataValue NVARCHAR(250),InGroup NVARCHAR(250))
Declare #Tbl_Insert Table (ID INT, Name NVARCHAR(250), Age INT)
-- Sample Data
Insert Into #Tbl1 values ('#Tbl_Insert','ID','INT','1','Group1'),('#Tbl_Insert','Name','NVARCHAR(250)','John.Adam','Group1'),('#Tbl_Insert','Age','INT','10','Group1')
Insert Into #Tbl1 values ('#Tbl_Insert','ID','INT','2','Group2'),('#Tbl_Insert','Name','NVARCHAR(250)','Andy.Law','Group2'),('#Tbl_Insert','Age','INT','18','Group2')
I can convert #tbl1 to row by row into #Table_TEMP
Declare #Table_TEMP (Data nvarchar(max))
Insert Into #Table_TEMP
SELECT LEFT([DataValues] , LEN([DataValues] )-1)
FROM #Tbl1 AS extern
CROSS APPLY
(
SELECT Concat('''', Replace( ISNULL([DataValue],''), '''','' ) + ''',')
FROM #Tbl1 AS intern
WHERE extern.InGroup = intern.InGroup
Order By InGroup, ColumnName
FOR XML PATH('')
) pre_trimmed ( [DataValues])
GROUP BY InGroup, [DataValues]
I have to extract the number of rows in #Tbl1 ( Or #Table_TEMP) to #Tbl_Insert.
I don't want to use cursor to loop Insert row by row in #Table_TEMP, because, when you met with big data (example > 10000 rows). It's run to slow.
Please help.
I found sample in stackorverflow
Declare #tbl_Temp Table (Data NVARCHAR(MAX))
Declare #tbl2 Table (A NVARCHAR(MAX),B NVARCHAR(MAX),C NVARCHAR(MAX))
Insert Into #tbl_Temp values ('a1*b1*c1')
INSERT INTO #tbl2 (A,B,C)
SELECT PARSENAME(REPLACE(Data,'*','.'),3)
,PARSENAME(REPLACE(Data,'*','.'),2)
,PARSENAME(REPLACE(Data,'*','.'),1)
FROM #tbl_Temp
select * from #tbl2
It's nearly the same, but,
My data have "DOT", can not use PARSENAME
I must know numbers of DOT to Build Dynamics SQL??
PARSENAME only support 3 "DOT", It's null when More Dot.
EXAMPLE:
Declare #ObjectName nVarChar(1000)
Set #ObjectName = 'HeadOfficeSQL1.Northwind.dbo.Authors'
SELECT
PARSENAME(#ObjectName, 5) as Server4,
PARSENAME(#ObjectName, 4) as Server,
PARSENAME(#ObjectName, 3) as DB,
PARSENAME(#ObjectName, 2) as Owner,
PARSENAME(#ObjectName, 1) as Object
If, i understand correctly you will need to use apply in order to fetch the records & insert the data into other table
insert into #Tbl_Insert (ID, Name, Age)
select max(a.id) [id], max(a.Name) [Name], max(a.Age) [Age] from #Tbl1 t
cross apply
(values
(case when t.ColumnName = 'ID' then t.DataValue end,
case when t.ColumnName = 'Name' then t.DataValue end,
case when t.ColumnName = 'Age' then t.DataValue end, t.InGroup)
) as a(id, Name, Age, [Group])
group by a.[Group]
select * from #Tbl_Insert
I do both #Tbl_Insert & create 1 store to do like PARSENAME. It's improved performance.
create function dbo.fnGetCsvPart(#csv varchar(8000),#index tinyint, #last bit = 0)
returns varchar(4000)
as
/* function to retrieve 0 based "column" from csv string */
begin
declare #i int; set #i = 0
while 1 = 1
begin
if #index = 0
begin
if #last = 1 or charindex(',',#csv,#i+1) = 0
return substring(#csv,#i+1,len(#csv)-#i+1)
else
return substring(#csv,#i+1,charindex(',',#csv,#i+1)-#i-1)
end
select #index = #index-1, #i = charindex(',',#csv,#i+1)
if #i = 0 break
end
return null
end
GO

Based on a variable: SQL Query to fetch data for multiple values from one column OR get all values from that column

Problem Statement :
when #a has a single word(Ex. 'name1') OR comma separated string (Example 'name1,name2,name3') then the query should return the manager names of employees with name1 and name2 and name3
when #a has an empty string then return the manager names of all the employees in the emp_master table
I have defined a stored procedure where I pass a variable.
This variable can be a comma separated string, a single word or an empty string.
If the string is comma separated then I split that string and get values based on the return table of split statement
else
I get the related value of the non comma separated data using normal subquery
I have tried to achieve this in the following way
Declare #a varchar(50)= ''
select emp.Name from
emp_master emp
where
(LEN(#a)=0 AND emp.Name in
(
SELECT DISTINCT [Name] FROM
[dbo].[Emp_Master] WHERE [EmpId] IN
(
SELECT
DISTINCT [MGR_ID]
FROM [dbo].[Emp_Master]
)
)
)
OR
emp.Name in (Select * from [dbo].[SplitString](#a, ','))
Details for the above sample:
[dbo].[SplitString] - custom written function : returns a table of split values. So
Select * from [dbo].SplitString
will return
SplitTable
----------
name1
name2
name3
and
Select * from [dbo].[SplitString](',','name1')
will return
SplitTable
----------
name1
[dbo].[Emp_Master] contains data for all the employees
[MGR_ID] is the column which has the employeeID of the employee manager
#a is the input variable
The Database is MS SQL 2008
My current solution(the above insane query) solves my purpose but it is very slow, it would be helpful to get an optimized and faster working solution for the problem
Emp_master Table has 400 000 rows, 30 columns
There are 18 000 managers in that table
CREATE NONCLUSTERED INDEX ix ON dbo.Emp_Master ([MGR_ID])
GO
DECLARE #a VARCHAR(50) = ''
DECLARE #t TABLE (val VARCHAR(50) PRIMARY KEY WITH(IGNORE_DUP_KEY=ON))
INSERT INTO #t
SELECT item = t.c.value('.', 'INT')
FROM (
SELECT txml = CAST('<r>' + REPLACE(#a, ',', '</r><r>') + '</r>' AS XML)
) r
CROSS APPLY txml.nodes('/r') t(c)
SELECT /*DISTINCT*/ [Name]
FROM dbo.Emp_Master e1
WHERE (
#a = ''
AND
e1.[EmpId] IN (SELECT DISTINCT MGR_ID FROM dbo.Emp_Master)
)
OR (
#a != ''
AND
e.Name IN (SELECT * FROM #t)
)
OPTION(RECOMPILE)
TRY THIS
CREATE NONCLUSTERED INDEX IX_MGR_ID_Emp_Master ON dbo.Emp_Master ([MGR_ID])
GO
Create Procedure searchname (#a varchar(255))
as
IF (#a = '')
BEGIN
EXEC Searchname1 #a
END
ELSE
BEGIN
EXEC Searchname2 #a
END
GO
Create Procedure Searchname1 (#a varchar(255))
AS
SELECT DISTINCT [Name] FROM
[dbo].[Emp_Master] m1 WHERE
exists
(
SELECT
*
FROM [dbo].[Emp_Master] m2
WHERE
m1.[EmpId]= m2.[MGR_ID]
)
GO
Create Procedure Searchname2 (#a varchar(max))
AS
Select #a = ' SELECT '''+replace( #a,',',''' Union ALL SELECT ''')+' '''
Create table #names (name varchar(255))
insert into #names
EXEC ( #a )
select emp.Name from
emp_master emp
WHERE
emp.Name in( Select name FRom #names)
option (recompile)
IF YOU ARE ALREADY DEALING WITH SQL INJECTION AT APPLICATION LEVEL
THEN
ALTER procedure [dbo].[Searchname2] (#a varchar(max))
AS
select #a = ''''+replace ( #a,',',''',''')+''''
DECLARE #sql NVARCHAR(MAX) = N'
select distinct emp.Name from
emp_master emp
WHERE
emp.Name in( '+#a+')'
EXEC (#sql)

How to call a recursive function in sql server

I have a table as follows
cat_id Cat_Name Main_Cat_Id
1 veg null
2 main course 1
3 starter 1
4 Indian 2
5 mexican 2
6 tahi 3
7 chinese 3
8 nonveg null
9 main course 8
10 indian 9
11 starter 8
12 tahi 11
13 chinese 11
(Main_Cat_Id is cat_id of previously added category in which it belongs)
This table is used for the categories the product where veg category has the two sub category main course and starter which is identify by main_cat_id
and those subcategories again has sub category as indian and mexican
And this categorization is dependent on the user; he can add more sub categories to indian, mexican also so that he can have any level of categorization
now I have to select all the subcategories of any node like if I take veg i have to select
(1)veg > (2)main course(1) > (4)indian(2)
> (5)mexican(2)
> (3)starter(1) > (6)thai(3)
> (7)chinese(3)
to form the string as 1,2,4,5,3,6,7
to do this i wrote a sql function as
CREATE FUNCTION [dbo].[GetSubCategory_TEST]
( #MainCategory int, #Category varchar(max))
RETURNS varchar(max)
AS
BEGIN
IF EXISTS (SELECT Cat_Id FROM Category WHERE Main_Cat_Id=#MainCategory)
BEGIN
DECLARE #TEMP TABLE
(
CAT_ID INT
)
INSERT INTO #TEMP(CAT_ID) SELECT Cat_Id FROM Category WHERE Main_Cat_Id=#MainCategory
DECLARE #TEMP_CAT_ID INT
DECLARE CUR_CAT_ID CURSOR FOR SELECT CAT_ID FROM #TEMP
OPEN CUR_CAT_ID
WHILE 1 =1
BEGIN
FETCH NEXT FROM CUR_CAT_ID
INTO #TEMP_CAT_ID;
IF ##FETCH_STATUS <> 0
SET #Category=#Category+','+ CONVERT(VARCHAR(50), #TEMP_CAT_ID)
SET #Category = [dbo].[GetSubCategory](#TEMP_CAT_ID,#Category)
END
CLOSE CUR_CAT_ID
DEALLOCATE CUR_CAT_ID
END
return #Category
END
but this function keep on executing and not gives the desired output i don't understands what wrong is going on plz help me to get this
You dont need a recursive function to build this, you can use a Recursive CTE for that.
Something like
DECLARE #TABLE TABLE(
cat_id INT,
Cat_Name VARCHAR(50),
Main_Cat_Id INT
)
INSERT INTO #TABLE SELECT 1,'veg',null
INSERT INTO #TABLE SELECT 2,'main course',1
INSERT INTO #TABLE SELECT 3,'starter',1
INSERT INTO #TABLE SELECT 4,'Indian',2
INSERT INTO #TABLE SELECT 5,'mexican',2
INSERT INTO #TABLE SELECT 6,'tahi',3
INSERT INTO #TABLE SELECT 7,'chinese',3
INSERT INTO #TABLE SELECT 8,'nonveg',null
INSERT INTO #TABLE SELECT 9,'main course',8
INSERT INTO #TABLE SELECT 10,'indian',9
INSERT INTO #TABLE SELECT 11,'starter',8
INSERT INTO #TABLE SELECT 12,'tahi',11
INSERT INTO #TABLE SELECT 13,'chinese',11
;WITH Recursives AS (
SELECT *,
CAST(cat_id AS VARCHAR(MAX)) + '\' ID_Path
FROM #TABLE
WHERE Main_Cat_Id IS NULL
UNION ALL
SELECT t.*,
r.ID_Path + CAST(t.cat_id AS VARCHAR(MAX)) + '\'
FROM #TABLE t INNER JOIN
Recursives r ON t.Main_Cat_Id = r.cat_id
)
SELECT *
FROM Recursives
I am ashamed, but I used #astander scipt to give string result.
First I created data you gave.
Second I collect rows which I need
And then using XML I put everything in one row (function STUFF removes first comma)
DECLARE #TABLE TABLE(
cat_id INT,
Cat_Name VARCHAR(50),
Main_Cat_Id INT
)
DECLARE #Collected TABLE(
cat_id INT
)
INSERT INTO #TABLE SELECT 1,'veg',null
INSERT INTO #TABLE SELECT 2,'main course',1
INSERT INTO #TABLE SELECT 3,'starter',1
INSERT INTO #TABLE SELECT 4,'Indian',2
INSERT INTO #TABLE SELECT 5,'mexican',2
INSERT INTO #TABLE SELECT 6,'tahi',3
INSERT INTO #TABLE SELECT 7,'chinese',3
INSERT INTO #TABLE SELECT 8,'nonveg',null
INSERT INTO #TABLE SELECT 9,'main course',8
INSERT INTO #TABLE SELECT 10,'indian',9
INSERT INTO #TABLE SELECT 11,'starter',8
INSERT INTO #TABLE SELECT 12,'tahi',11
INSERT INTO #TABLE SELECT 13,'chinese',11
INSERT INTO #TABLE SELECT 14,'chinese',6
DECLARE #nodeID INT = 1;
DECLARE #result VARCHAR(MAX);
;WITH Recursives AS (
SELECT cat_id, main_cat_id
FROM #TABLE
WHERE Cat_Id = #nodeID
UNION ALL
SELECT T.cat_id, T.main_cat_id
FROM #TABLE AS T
INNER JOIN Recursives AS R
ON t.Main_Cat_Id = r.cat_id
)
INSERT INTO #Collected
SELECT cat_id
FROM Recursives
SELECT #result = STUFF(
(SELECT ',' + CAST( cat_id AS VARCHAR)
FROM #Collected
ORDER BY cat_id
FOR XML PATH('')
), 1,1,'')
SELECT #result
Your cursor is looping infinitely because you asked it to keep going until 1 no longer equals 1:
WHILE 1 =1
1=1 is always true so the loop never ends, and you don't explicitly break out of it anywhere.
You would do well to study some examples of cursors, for example this one in the Microsoft T-SQL documentation. They are quite formulaic and the main syntax rarely needs to vary much.
The standard approach after opening the cursor is to do an initial fetch next to get the first result, then open a while loop conditional on ##FETCH_STATUS = 0 (0 meaning successful).
Because you're looking only for unsuccessful cursor fetch states inside your cursor:
IF ##FETCH_STATUS <> 0
The setting of #Category will only happen once the cursor has gone past the last row in the set. I suspect this is exactly what you don't want.
I'm also not sure about the scoping of the #Category variable, since it's an input parameter to the function; I generally create new variables inside a function to work with, but off the top of my head I'm not sure this will actually create a problem or not.
More generally, although I don't totally understand what you're trying to achieve here, a recursive function involving a cursor is probably not the right way to do it, as Adriaan Stander's answer suggests.

grouping, splitting, and counting rows

given this table and data:
DECLARE #Table table (RowID int, RowCode char(1), RowValue int);set nocount on
INSERT #Table VALUES ( 6,'A',3757 )
INSERT #Table VALUES ( 5,'A',37827)
INSERT #Table VALUES (14,'A',48411)
INSERT #Table VALUES ( 1,'A',48386)
INSERT #Table VALUES (20,'A',48450)
INSERT #Table VALUES ( 7,'A',46155)
INSERT #Table VALUES (13,'A',721 )
INSERT #Table VALUES ( 2,'A',49335)
INSERT #Table VALUES (15,'A',4700 )
INSERT #Table VALUES (19,'A',64416)
INSERT #Table VALUES ( 8,'A',27246)
INSERT #Table VALUES (12,'B',54929)
INSERT #Table VALUES (16,'B',3872 )
INSERT #Table VALUES ( 3,'C',728 )
INSERT #Table VALUES (11,'C',1050 )
INSERT #Table VALUES ( 9,'C',3191 )
INSERT #Table VALUES (17,'C',866 )
INSERT #Table VALUES ( 4,'C',838 )
INSERT #Table VALUES (10,'D',550 )
INSERT #Table VALUES (18,'D',1434 );set nocount off
I need this:
VVVVVVVV
RowID RowCode RowValue RowChunk
----- ------- -------- --------
1 A 48386 1
2 A 49335 1
5 A 37827 1
6 A 3757 1
7 A 46155 1
8 A 27246 2
13 A 721 2
14 A 48411 2
15 A 4700 2
19 A 64416 2
20 A 48450 3
12 B 54929 4
16 B 3872 4
3 C 728 5
4 C 838 5
9 C 3191 5
11 C 1050 5
17 C 866 5
10 D 550 6
18 D 1434 6
RowChunk starts at 1 and is incremented by 1 for each RowCode change and/or when there have been 5 of the same RowCode values.
Basically my solution uses the same approach as yours, only with slightly different devices employed.
WITH NumberedRows AS (
SELECT
RowID,
RowCode,
RowValue,
CodeChunk = (ROW_NUMBER() OVER (PARTITION BY RowCode ORDER BY RowID) - 1) / 5
FROM #Table
)
SELECT
RowID,
RowCode,
RowValue,
RowChunk = DENSE_RANK() OVER (ORDER BY RowCode, CodeChunk)
FROM NumberedRows
I don't think there's an analysis function, or any reasonable combination of such, which will address this. You'll have to do it RBAR with a cursor or, slightly faster in my experience, a loop.
This example of looping assumes that RowID is unique. If RowID is not the clustered PK, this will be very slow, so if that's the case you'll want to create a temp table.
DECLARE #RowID INT = (SELECT MIN(RowID) FROM #Table)
DECLARE #MaxRowID INT = (SELECT MAX(RowID) FROM #Table)
DECLARE #RowCode CHAR(1)
DECLARE #LastRowCode CHAR(1)
DECLARE #RowValue INT
DECLARE #Chunk INT = 0
DECLARE #RecsThisChunk INT
DECLARE #Results TABLE (RowID INT NOT NULL PRIMARY KEY, RowCode CHAR(1) NOT NULL, RowValue INT NOT NULL, Chunk INT NOT NULL)
WHILE #RowID <= #MaxRowID
BEGIN
-- Handle gaps in RowID
IF NOT EXISTS (SELECT * FROM #Table WHERE RowID = #RowID) GOTO EndOfLoop
-- Load values for this record
SELECT #RowCode = RowCode, #RowValue = RowValue FROM #Table WHERE RowID = #RowID
IF #LastRowCode IS NULL OR #RowCode <> #LastRowCode OR #RecsThisChunk = 5
BEGIN
-- Start a new chunk
SET #Chunk = #Chunk + 1
SET #RecsThisChunk = 1
END
ELSE
BEGIN
-- Same chunk
SET #RecsThisChunk = #RecsThisChunk + 1
END
SET #LastRowCode = #RowCode
INSERT INTO #Results (RowID, RowCode, RowValue, Chunk) VALUES (#RowID, #RowCode, #RowValue, #Chunk)
EndOfLoop:
SET #RowID = #RowID + 1
END
SELECT * FROM #Results
You may have tweak this a bit for 2005, I use 2008 routinely and don't recall all the little differences.
FYI, the results you show don't quite match the sample data.
Hope this helps! The only alternative I see is a cursor, or handling this in the application layer.
this does the trick without a loop:
;WITH NumberedRows AS (
SELECT
r.RowID, r.RowCode, r.RowValue, CEILING(ROW_NUMBER() OVER(PARTITION BY r.RowCode ORDER BY r.RowCode,r.RowID)/5.0) AS CodeRowChunk
FROM #Table r
)
, AllChunks AS (
SELECT r.*,ROW_NUMBER() OVER(ORDER BY RowCode,CodeRowChunk) AS ChunkRowNumber
FROM (SELECT DISTINCT
RowCode, CodeRowChunk
FROM NumberedRows) r
)
SELECT
a.RowID, RowCode, a.RowValue,
(SELECT ChunkRowNumber FROM AllChunks c WHERE c.RowCode=a.RowCode and c.CodeRowChunk=a.CodeRowChunk) AS RowChunk
FROM NumberedRows a
This is the answer you are looking for :
create Table [table] (RowID int, RowCode char(1), RowValue int)
INSERT [Table] VALUES ( 6,'A',3757 )
INSERT [Table] VALUES ( 5,'A',37827)
INSERT [Table] VALUES (14,'A',48411)
INSERT [Table] VALUES ( 1,'A',48386)
INSERT [Table] VALUES (20,'A',48450)
INSERT [Table] VALUES ( 7,'A',46155)
INSERT [Table] VALUES (13,'A',721 )
INSERT [Table] VALUES ( 2,'A',49335)
INSERT [Table] VALUES (15,'A',4700 )
INSERT [Table] VALUES (19,'A',64416)
INSERT [Table] VALUES ( 8,'A',27246)
INSERT [Table] VALUES (12,'B',54929)
INSERT [Table] VALUES (16,'B',3872 )
INSERT [Table] VALUES ( 3,'C',728 )
INSERT [Table] VALUES (11,'C',1050 )
INSERT [Table] VALUES ( 9,'C',3191 )
INSERT [Table] VALUES (17,'C',866 )
INSERT [Table] VALUES ( 4,'C',838 )
INSERT [Table] VALUES (10,'D',550 )
INSERT [Table] VALUES (18,'D',1434 )
IF object_id('tempdb..#tempTable') IS NOT NULL
BEGIN
DROP TABLE #tempTable
END
CREATE TABLE #tempTable
(RowID int, RowCode char(1), RowValue int,RowChunk int)
INSERT INTO #tempTable
select RowID,RowCode,RowValue,null from [table]
declare #RowId int
declare #RowCode char(1)
declare #Count int
declare #CurrentCode char(1)
declare #CountCurrent int
set #Count=1
set #CurrentCode=1
set #CountCurrent=0
DECLARE contact_cursor CURSOR FOR
SELECT RowID,RowCode FROM [table]
OPEN contact_cursor
FETCH NEXT FROM contact_cursor into #RowId,#RowCode
set #CurrentCode=#RowCode
WHILE ##FETCH_STATUS = 0
BEGIN
if(#CurrentCode=#RowCode)
begin
if(#CountCurrent=5)
begin
set #CountCurrent=1
set #Count=#Count+1
update #tempTable set RowChunk=#Count where RowID=#RowID
end
else
begin
set #CountCurrent=#CountCurrent+1
update #tempTable set RowChunk=#Count where RowID=#RowID
end
end
else
begin
set #CurrentCode=#RowCode
set #CountCurrent=1
set #Count=#Count+1
update #tempTable set RowChunk=#Count where RowID=#RowID
end
FETCH NEXT FROM contact_cursor into #RowId,#RowCode
END
CLOSE contact_cursor
DEALLOCATE contact_cursor
select * from #tempTable
GO

Insert XML data into SQL Server table

My data looks like below:
<products>
<product ProductID="1" Price="79.99" Weight="30.00" Quantity="1">
<addon ProductAddonID="0" ControlTypeID="9" Price="25.00" Weight="0.00" Quantity="1" Name="yyy" Data="ASD" />
<addon ProductAddonID="89" ControlTypeID="0" Price="15.00" Weight="4.00" Quantity="1" Name="xxx" Data="" />
</product>
</products>
My SQL code looks like this:
INSERT INTO [Order].Items(OrderID, ProductID, Price, Weight, Quantity)
SELECT #OrderID, ProductID, Price, Weight, Quantity
FROM OPENXML (#XmlHandle, '/products/product',1)
WITH (ProductID INT '#ProductID',
Price DECIMAL(6,2) '#Price',
Weight DECIMAL(6,2) '#Weight',
Quantity INT '#Quantity')
SET #OrderItemId = SCOPE_IDENTITY()
INSERT INTO [Order].Addons(OrderItemID, ProductAddonID, ControlTypeID, Price, Weight, Quantity, [Name], DATA)
SELECT #OrderItemId, ProductAddonID, ControlTypeID, Price, Weight, Quantity, [Name], [Data]
FROM OPENXML(#XMLHandle, '/products/product/addon',1)
WITH (
ProductAddonID INT,
ControlTypeID INT,
Price DECIMAL(6,2),
Weight DECIMAL(6,2),
Quantity INT,
[Name] NVARCHAR(500),
[Data] NVARCHAR(max)
)
When I have multiple products/addons, all of the addons are inserting with the latest #OrderItemID ... I'm not sure how to work in my SQL that inserts the addon into the loop that iterates through the product nodes.
Could anyone point me in the right direction?
thanks in advance!
I think,
You need to insert records in Loop to get SCOPE_IDENTITY.
First put Order.Items datain temp table and then loop on it to insert in Order.Items table.
Following is the idea -- Not working code.
DECLARE #count INT
DECLARE #id INT
SET #count = 1
SET #id = totalNumberOfRecordsInTempTable -- Get records from xml to temp table first
WHILE #count <= #id
BEGIN
INSERT INTO YourTable (Column1, Column2, ...)
SELECT Column1, Column2, ... FROM SourceTable WHERE Id = #count
SET #count = #count + 1
SET #OrderItemId = SCOPE_IDENTITY()
INSERT INTO Order.AddOns
END
I have checked it and in loop you can get the SCOPE_IDENTITY.
declare #table table
(
id int,
quanity int
)
insert into #table select 1, 10
insert into #table select 2, 20
insert into #table select 3, 30
insert into #table select 4, 40
declare #table2 table
(
orderid int identity(1, 1),
quanity int
)
declare #id int
select #id = max(id) from #table
while #id > 0
begin
insert into #table2 (quanity)
select quanity from #table where id = #id
set #id = #id - 1
select SCOPE_IDENTITY()
end

Resources