Self joins and Not in combined - sql

I need to write a query scanning 2 tables in a way that the record after self join in one table should not be present in second table if they have certain condition.
If an order is received we insert into UniqueReference Table that has unique constraints on reference combination (data1,data2,reference,identifier)
But it could be that order get Rejected or Cancelled and next order might come with same reference combination. I have to make sure I still allow it.
I give an example below for test data :
UniqueReference Table
-------
sequence data1 data2 key reference identifier
1 XYZB ABCD 234 Reference1 ID2
2 XYZB DCBF 456 Reference2 ID2
3 XYZB null 678 Reference3 null
4 XYZB ABCD 980 Reference1 ID2
Order Table
--------
sequence key status
1 234 Created
2 456 Rejected
3 789 Processed
4 980 Cancelled
5 678 Processing
Now with above two data set when I receive an order (so say key 980) with reference combination (XYZB,ABCD,Reference1,ID2) then system should not allow that order (it is duplicate) because earlier we received such order with key (234) whose status is not Rejected. But if we receive new order with combination (XYZB,DCBF,Reference2,ID2) then we should allow this order because we do have that order in system but its status is Rejected.
I am needing something like
Select count(*) from Order o where o.status <> 'Rejected' and o.key in
(select <self-join> on reference combination on key for newly received order)

I think you're mostly confusing yourself with this setup.
As for the UniqueReference table. If you say the combination data1, data2, reference, identifier is UNIQUE, well, then it should be just that: UNIQUE. It doesn't matter nor should care about what happens elsewhere.
Remark: I'm assuming the key field is unique too, and if it is, I do wonder why you don't simply use the autonumber/identity/... for it which you now seem to assign to the sequence column, which has no real value IMHO. Right now I can't tell how you produced these key values.
Now for the Order table, here you could foresee logic that says: if we don't have a previous record for this key yet, allow INSERT operation. If there is a previous one, find the most recent one and if it says 'Cancelled' then allow the INSERT too. Otherwise we always block the INSERT.
I'm not sure how you would like to do this, but I guess a stored procedure would make sense in this case.
PS: this code is far from perfect (for starters, it's NOT tested!), has no error-handling and probably can be optimized quite a bit (e.g. by merging certain operations, less branching, etc). But I think its verbosity makes it easier to read and since premature optimization is the root of all evil you might want to work it out like this first and optimize as needed when it turns out to be too slow.
(since you didn't mention RDBMS, I'm using T-SQL syntax, but I think it is sufficiently generic to run on most systems with minor tweaking...)
CREATE PROCEDURE p_insert_order (
#data1 varchar(100),
#data2 varchar(100),
#reference varchar(100),
#identifier varchar(100),
#status varchar(100)
)
AS
DECLARE #key int,
#is_new_key bit,
#allow_insert bit,
#last_status varchar(100)
SELECT #key = NULL,
#is_new_key = 0,
#allow_insert = 0,
#last_status = NULL
BEGIN TRANSACTION
-- do we already have a key for this combination?
SELECT #key = [key]
FROM [UniqueReference] WITH (UPDLOCK, HOLDLOCK)
WHERE data1 = #data1
AND data2 = #data2
AND reference = #reference
AND identifier = #identifier
IF #key IS NULL
BEGIN
SELECT #is_new_key = 1,
#key = 0 -- ??? -- I have no clue how you come up with these so I'm going to leave it open
INSERT [UniqueReference] (data1, data2, reference, identifier, [key])
VALUES (#data1, #data2, #reference, #identifier, #key)
END
-- do we allow insert?
SELECT #allow_insert = #is_new_key
IF #allow_insert = 0
BEGIN
SELECT TOP 1 #last_status = [status]
FROM [Order] WITH (UPDLOCK, HOLDLOCK)
WHERE [key] = #key
ORDER BY sequence DESC
SELECT #allow_insert = 1
WHERE #last_status IS NULL
OR #last_status = 'Rejected'
END
-- do we do insert?
IF #allow_insert = 1
BEGIN
INSERT [Order] ([key], [status])
VALUES (#key, #status)
END
COMMIT TRANSACTION
Return(0)
PS: Try to avoid using reserved words, Order, key, status, ...

First of all you have to add key column in UniqueReference table to the unique constraint so it will be (data1,data2,reference,identifier,key)
Then you can use this query
;with
old_orders as (
select distinct data1, data2, [reference], [identifier]
from UniqueReference u
where not exists(select top 1 1 from Order o where u.[key] = o.[key] and o.status in ('Cancelled','Rejected'))
)
insert into #UniqueReference (data1, data2, [reference], [identifier], [key])
select #data1, #data2, #reference, #identifier, #key
where exists (
select #data1, #data2, #reference, #identifier
except
select * from old_orders o
)
With these values the insert will be rejected
declare
#data1 varchar(4)='XYZB',
#data2 varchar(4)='ABCD',
#key int = 980,
#reference varchar(10)='Reference1',
#identifier varchar(4)='ID2'
With these values the insert will be accepted
declare
#data1 varchar(4)='XYZB',
#data2 varchar(4)='DCBF',
#key int = 999,
#reference varchar(10)='Reference2',
#identifier varchar(4)='ID2'

Related

SQL Server: automatically add a unique identifier to all rows inserted at one time

The below SQL Server code successfully calculates and inserts the monthly pay for all employees along with their staffID number and inserts it into Tablepayroll.
INSERT INTO Tablepayroll (StaffID,Totalpaid)
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay
FROM Tabletimelog
JOIN Tablestaff ON
Tabletimelog.StaffID = Tablestaff.StaffID)
However, I want to be able to also insert a batchIDso that you can identify each time the above insert has been run and the records inserted by it at that time. Meaning that all staff payroll calculated at the same time would have the same batchID number. Each subsequent batchID should just increase by 1.
Please see image below for visual explanation .
I think that Select MAX(batch_id) + 1 would work , but I don't know how to include it in the insert statement.
You can use subquery to find latest batch_id from your current table using this query:
INSERT INTO TablePayroll (StaffID, TotalPaid, batch_id)
SELECT T1.StaffID
, T1.HoursWorked * T2.HourlyPay
, ISNULL((SELECT MAX(batch_id) FROM TablePayRoll), 0) + 1 AS batch_id
FROM TableTimeLog AS T1
INNER JOIN TableStaff AS T2
ON T1.StaffID = T2.StaffID;
As you can see, I just add 1 to current MAX(batch_id) and that's it.
By the way, learn to use aliases. It will make your life easier
Yet another solution would be having your batch_id as a GUID, so you wouldn't have to create sequences or get MAX(batch_id) from current table.
DECLARE #batch_id UNIQUEIDENTIFIER = NEWID();
INSERT INTO TablePayroll (StaffID, TotalPaid, batch_id)
SELECT T1.StaffID, T1.HoursWorked * T2.HourlyPay, #batch_id
FROM TableTimeLog AS T1
INNER JOIN TableStaff AS T2
ON T1.StaffID = T2.StaffID;
Updated
First of all obtain the maximum value in a large table (based on the name of the table it must be big) can be very expensive. Especially if there is no index on the column batch_id
Secondly, pay attantion your solution SELECT MAX(batch_id) + 1 may behave incorrectly when you will have competitive inserts. Solution from #EvaldasBuinauskas without opening transaction and right isolation level can also lead to same batch_id if you run the two inserts at the same time in parallel.
If your SQL Server ver 2012 or higer you can try SEQUENCE. This at least ensures that no duplicates batch_id
Creating SEQUENCE:
CREATE SEQUENCE dbo.BatchID
START WITH 1
INCREMENT BY 1 ;
-- DROP SEQUENCE dbo.BatchID
GO
And using it:
DECLARE #BatchID INT
SET #BatchID = NEXT VALUE FOR dbo.BatchID;
INSERT INTO Tablepayroll (StaffID,Totalpaid, batch_id)
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay, #BatchID
FROM Tabletimelog
JOIN Tablestaff ON Tabletimelog.StaffID = Tablestaff.StaffID)
An alternative SEQUENCE may be additional table:
CREATE TABLE dbo.Batch (
ID INT NOT NULL IDENTITY
CONSTRAINT PK_Batch PRIMARY KEY CLUSTERED
,DT DATETIME
CONSTRAINT DF_Batch_DT DEFAULT GETDATE()
);
This solution works even on older version of the server.
DECLARE #BatchID INT
INSERT INTO dbo.Batch (DT)
VALUES (GETDATE());
SET #BatchID = SCOPE_IDENTITY();
INSERT INTO Tablepayroll (StaffID,Totalpaid, batch_id)
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay, #BatchID
FROM Tabletimelog ...
And yes, all of these solutions do not guarantee the absence of holes in the numbering. This can happen during a transaction rollback (deadlock for ex.)

SQL - Copy Data Within Same Table

I'm not that great with SQL Server, but I'm trying to do some behind the scenes work to create some functionality that our EMR system lacks - copying forms (and all their data) between patients.
In SQL Server 2008 R2 I have three tables that deal with these forms that have been filled out:
**Table 1**
encounter_id patient_id date time etc etc etc etc
1234 112233 2014-01-02 14:25:01:00 a b c d
**Table 2**
encounter_id page recorded_on recorded_by etc etc
1234 1 2014-01-02 134 asdf asdf
1234 2 2014-01-02 134 jkl; jkl;
**Table 3**
encounter_id page keyname keyvalue
1234 1 key1 aaa
1234 1 key2 bbb
1234 1 key3 ccc
1234 1 key4 ddd
1234 2 key5 eee
1234 2 key6 fff
1234 2 key7 ggg
As you can see, they all match together with the encounter_id, which is linked to the patient_id (In the first table).
What I'm trying to be able to do is copy all the rows in these three tables for a particular encounter_id back into the same table they come from, but with a different (system generated) encounter_id for a patient_id that I would specify. In essence, copying the form from one patient to another.
Any help on this is greatly appreciated.
I always like creating sample tables in [tempdb] so that the syntax is correct. I created tables [t1], [t2], and [t3]. There are primary and foreign keys.
If you have a well developed schema, ERD (entity relationship diagram) http://en.wikipedia.org/wiki/Entity-relationship_diagram , these relationships should be in place.
-- Playing around
use tempdb
go
--
-- Table 1
--
-- Remove if it exists
if object_id('t1') > 0
drop table t1
go
-- Create the first table
create table t1
(
encounter_id int,
patient_id int,
the_date date,
the_time time,
constraint pk_t1 primary key (encounter_id)
);
go
-- Add one row
insert into t1 values (1234, 112233, '2014-01-02', '14:25:01:00');
go
-- Show the data
select * from t1
go
--
-- Table 2
--
-- Remove if it exists
if object_id('t2') > 0
drop table t2
go
-- Create the second table
create table t2
(
encounter_id int,
the_page int,
recorded_on date,
recorded_by int,
constraint pk_t2 primary key (encounter_id, the_page)
);
go
-- Add two rows
insert into t2 values
(1234, 1, '2014-01-02', 134),
(1234, 2, '2014-01-02', 134);
go
-- Show the data
select * from t2
go
--
-- Table 3
--
-- Remove if it exists
if object_id('t3') > 0
drop table t3
go
-- Create the third table
create table t3
(
encounter_id int,
the_page int,
key_name1 varchar(16),
key_value1 varchar(16),
constraint pk_t3 primary key (encounter_id, the_page, key_name1)
);
go
-- Add seven rows
insert into t3 values
(1234, 1, 'key1', 'aaa'),
(1234, 1, 'key2', 'bbb'),
(1234, 1, 'key3', 'ccc'),
(1234, 1, 'key4', 'ddd'),
(1234, 2, 'key5', 'eee'),
(1234, 2, 'key6', 'fff'),
(1234, 2, 'key7', 'ggg');
go
-- Show the data
select * from t3
go
--
-- Foreign Keys
--
alter table t2 with check
add constraint fk_t2 foreign key (encounter_id)
references t1 (encounter_id);
alter table t3 with check
add constraint fk_t3 foreign key (encounter_id, the_page)
references t2 (encounter_id, the_page);
Here comes the fun part, a stored procedure to duplicate the data.
--
-- Procedure to duplicate one record
--
-- Remove if it exists
if object_id('usp_Duplicate_Data') > 0
drop procedure t1
go
-- Create the procedure
create procedure usp_Duplicate_Data #OldId int, #NewId int
as
begin
-- Duplicate table 1's data
insert into t1
select
#NewId,
patient_id,
the_date,
the_time
from t1
where encounter_id = #OldId;
-- Duplicate table 2's data
insert into t2
select
#NewId,
the_page,
recorded_on,
recorded_by
from t2
where encounter_id = #OldId;
-- Duplicate table 3's data
insert into t3
select
#NewId,
the_page,
key_name1,
key_value1
from t3
where encounter_id = #OldId;
end
Last but not least, we have to call the stored procedure to make sure it works.
-- Sample call
exec usp_Duplicate_Data 1234, 7777
In summary, I did not add any error checking or accounted for a range of Id's. I leave these tasks for you to learn.
Made a little fiddle as an example, here (link)
The solution is perhaps needlessly complex but it offers a good variety of other useful stuff as well, I just wanted to test how to build that dynamically. The script does print out the commands, making it relatively easy to remove the TSQL and just produce the plain-SQL to do as you wish.
What it does, is that it requires an encounter_id, which it will then use to dynamically fetch the columns (with the assumption that encounter_id is the PK for TABLE_1) to insert a new record in TABLE_1, store the inserted.encounter_id value, and use that value to fetch and copy the matching rows from TABLE_2 and TABLE_3.
Basically, as long as the structure is correct (TABLE_1 PK is encounter_id which is an identity type), you should be able to just change the table names referenced in the script and it should work directly regardless of which types of columns (and how many of them) your particular tables have.
The beef of the script is this:
/* Script begins here */
DECLARE #ENCOUNTER_ID INT, #NEWID INT, #SQL VARCHAR(MAX), #COLUMNS VARCHAR(MAX)
IF OBJECT_ID('tempdb..##NEW_ID') IS NOT NULL
DROP TABLE ##NEW_ID
CREATE TABLE ##NEW_ID (ID INT)
/* !!! SET YOUR DESIRED encounter_id RECORDS TO BE COPIED, HERE !!! */
SET #ENCOUNTER_ID = 1234
IF EXISTS (SELECT TOP 1 1 FROM TABLE_1 WHERE encounter_id = #ENCOUNTER_ID)
BEGIN
SELECT #COLUMNS = COALESCE(#COLUMNS+', ', 'SELECT ')+name
FROM sys.columns WHERE OBJECT_NAME(object_id) = 'TABLE_1' AND name <> 'encounter_id'
SET #COLUMNS = 'INSERT INTO TABLE_1 OUTPUT inserted.encounter_id INTO ##NEW_ID '+#COLUMNS+' FROM TABLE_1 WHERE encounter_id = '+CAST(#ENCOUNTER_ID AS VARCHAR(25))
EXEC(#COLUMNS)
PRINT(#COLUMNS)
SELECT TOP 1 #NEWID = ID, #COLUMNS = NULL FROM ##NEW_ID
SELECT #COLUMNS = COALESCE(#COLUMNS+', ', '')+name
FROM sys.columns WHERE OBJECT_NAME(object_id) = 'TABLE_2'
SET #COLUMNS = 'INSERT INTO TABLE_2 ('+#COLUMNS+') SELECT '+REPLACE(#COLUMNS,'encounter_id',''+CAST(#NEWID AS VARCHAR(25))+'')
+' FROM TABLE_2 WHERE encounter_id = '+CAST(#ENCOUNTER_ID AS VARCHAR(25))
EXEC(#COLUMNS)
PRINT(#COLUMNS)
SET #COLUMNS = NULL
SELECT #COLUMNS = COALESCE(#COLUMNS+', ', '')+name
FROM sys.columns WHERE OBJECT_NAME(object_id) = 'TABLE_3'
SET #COLUMNS = 'INSERT INTO TABLE_3 ('+#COLUMNS+') SELECT '+REPLACE(#COLUMNS,'encounter_id',''+CAST(#NEWID AS VARCHAR(25))+'')
+' FROM TABLE_3 WHERE encounter_id = '+CAST(#ENCOUNTER_ID AS VARCHAR(25))
EXEC(#COLUMNS)
PRINT(#COLUMNS)
IF OBJECT_ID('tempdb..##NEW_ID') IS NOT NULL
DROP TABLE ##NEW_ID
END
declare #oldEncounterID int
set #oldEncounterID = 1234
declare #newEncounterID int
set #newEncounterID = 2345
insert into table1(encounter_id, patient_id, date, time, etc)
select newEncounterID, patient_id, date, time, etc
from table1 where encounter_id = oldEncounterID
and so on... problem with this approach you must know in advantage what all the columns are, and if they change you may change the columns accordingly
Another approach:
declare #oldEncounterID int
set #oldEncounterID = 1234
declare #newEncounterID int
set #newEncounterID = 2345
select * into #table1 from table1 where encounter_id = oldEncounterID
update #table1 set encounter_id = newEncounterID
insert into table1 select * from #table1
and so on... this second approach however may need a little adjustment if there is an identity column then you'll have to set identity_insert to on
Psuedo code, not tested:
DECLARE #patient_id INT, #date datetime, #time ??
SET #patient_id = 112244 --your patient id
INSERT INTO [**Table 1**] (patient_id, date, time, etc, etc, etc, etc)
VALUES (#patient_id, #date, #time, 'a', 'b', 'c', 'd')
DECLARE #encounter_id int
SET #encounter_id = SCOPE_IDENTITY -- or select #encounter_id = encounter_id from [**Table 1**] where patientId = #patient_id
INSERT INTO [**Table 2**] (encounter_id, page, recorded_on, recorded_by, etc, etc2)
SELECT #encounter_id, page, recorded_on, recorded_by, etc, etc2
FROM [**Table 2**]
WHERE encounter_id = 1234
INSERT INTO [**Table 3**] (encounter_id, page, keyname, keyvalue)
SELECT #encounter_id, page, keyname, keyvalue
FROM [**Table 3**]
WHERE encounter_id = 1234

Generating unique values

There is a column 'Keys' in a table. With data Like this
Key Name
1 aaa
2 sads
null asd
null asd
Now I need to replace null values with 3 and 4. How can I do that.
Depending on which version of SQL Server you're working with, you'd use TOP or SET ROWCOUNT to limit an UPDATE to a single row. Something like this will work:
select top 1 * from sysobjects
WHILE ##ROWCOUNT > 0
BEGIN
UPDATE TOP 1 Keys SET Key = (SELECT MAX(Key) from Keys)+1 WHERE Key is null
END
But isn't ideal. I can't think of another way of addressing the duplicate rows - unless this is a one-off task, in which case temporarily adding an IDENTITY column would work.
If you can put the data (temporarily) into a separate table you can use ROW_COUNT():
declare #Keys table ([Key] int not null, [Name] varchar(50) null);
insert into #Keys ([Key], [Name])
select [Key], [Name]
from [Keys]
where [Key] is not null
union all
select [Key] = row_number() over (order by [Name]) +
(select max([Key]) from [Keys]),
[Name]
from [Keys]
where [Key] is null;
truncate table [Keys];
insert into [Keys] select * from #Keys;

Insert record only if record does not already exist in table

I'm wondering if there is a way to insert a record into a table only if the table does not already contain that record?
Is there a query that will do this, or will I need a stored procedure?
You don't say what version of SQL Server. If SQL Server 2008 you can use MERGE
NB: It is usual to use Merge for an Upsert which is what I originally thought the question was asking but it is valid without the WHEN MATCHED clause and just with a WHEN NOT MATCHED clause so does work for this case also. Example Usage.
CREATE TABLE #A(
[id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[C] [varchar](200) NOT NULL)
MERGE #A AS target
USING (SELECT 3, 'C') AS source (id, C)
ON (target.id = source.id)
/*Uncomment for Upsert Semantics
WHEN MATCHED THEN
UPDATE SET C = source.C */
WHEN NOT MATCHED THEN
INSERT (id, C)
VALUES (source.id, source.C);
In terms of execution costs the two look roughly equal when an Insert is to be done...
Link to plan images for first run
but on the second run when there is no insert to be done Matthew's answer looks lower cost. I'm not sure if there is a way of improving this.
Link to plan images for second run
Test Script
select *
into #testtable
from master.dbo.spt_values
CREATE UNIQUE CLUSTERED INDEX [ix] ON #testtable([type] ASC,[number] ASC,[name] ASC)
declare #name nvarchar(35)= 'zzz'
declare #number int = 50
declare #type nchar(3) = 'A'
declare #low int
declare #high int
declare #status int = 0;
MERGE #testtable AS target
USING (SELECT #name, #number, #type, #low, #high, #status) AS source (name, number, [type], low, high, [status])
ON (target.[type] = source.[type] AND target.[number] = source.[number] and target.[name] = source.[name] )
WHEN NOT MATCHED THEN
INSERT (name, number, [type], low, high, [status])
VALUES (source.name, source.number, source.[type], source.low, source.high, source.[status]);
set #name = 'yyy'
IF NOT EXISTS
(SELECT *
FROM #testtable
WHERE [type] = #type AND [number] = #number and name = #name)
BEGIN
INSERT INTO #testtable
(name, number, [type], low, high, [status])
VALUES (#name, #number, #type, #low, #high, #status);
END
IF NOT EXISTS
(SELECT {Columns}
FROM {Table}
WHERE {Column1 = SomeValue AND Column2 = SomeOtherVale AND ...})
INSERT INTO {Table} {Values}
In short, you need a table guaranteed to provide you the ability to return one row:
Insert dbo.Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3',....
From Information_Schema.Tables
Where Table_Schema = 'dbo'
And Table_Name = 'Table'
And Not Exists (
Select 1
From dbo.Table
Where Col1 = 'Foo'
And Col2 = 'Bar'
And ....
)
I've seen this variation in the wild as well:
Insert Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3'....
From (
Select 1 As Num
) As Z
Where Not Exists (
Select 1
From Table
Where Col1 = Foo
And Col2 = Bar
And ....
)
I have to vote for adding a CONSTRAINT. It's the simplest and the most robust answer. I mean, looking at how complicated the other answers are I'd say they're much harder to get right (and keep right).
The downsides: [1] it's not obvious from reading the code that uniqueness is enforced in the DB [2] the client code has to know to catch an exception. In other words, the guy coming after you might wonder "how did this ever work?"
That aside: I used to worry that throwing/catching the exception was a performance hit but I did some testing (on SQL Server 2005) and it wasn't significant.

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