large insert in two tables. First table will feed second table with its generated Id - sql

One question about how to t-sql program the following query:
Table 1
I insert 400.000 mobilephonenumbers in a table with two columns. The number to insert and identity id.
Table 2
The second table is called SendList. It is a list with 3columns, a identity id, a List id, and a phonenumberid.
Table 3
Is called ListInfo and contains PK list id. and info about the list.
My question is how should I using T-sql:
Insert large list with phonenumbers to table 1, insert the generated id from the insert of phonenum. in table1, to table 2. AND in a optimized way. It cant take long time, that is my problem.
Greatly appreciated if someone could guide me on this one.
Thanks
Sebastian

What version of SQL Server are you using? If you are using 2008 you can use the OUTPUT clause to insert multiple records and output all the identity records to a table variable. Then you can use this to insert to the child tables.
DECLARE #MyTableVar table(MyID int);
INSERT MyTabLe (field1, field2)
OUTPUT INSERTED.MyID
INTO #MyTableVar
select Field1, Field2 from MyOtherTable where field3 = 'test'
--Display the result set of the table variable.
Insert MyChildTable (myID,field1, field2)
Select MyID, test, getdate() from #MyTableVar
I've not tried this directly with a bulk insert, but you could always bulkinsert to a staging table and then use the processs, described above. Inserting groups of records is much much faster than one at a time.

Related

How to copy some records of table and change some columns before insert into this table again in sql server?

In my SQL Server table, I have a table whose PK is GUID with lots of records already.
Now I want to add records which only needs to change the COMMON_ID and COMMON_ASSET_TYPE column of some existing records.
select * from My_Table where COMMON_ASSET_TYPE = "ASSET"
I am writing sql to copy above query result, changing COMMON_ID value to new GUID value and COMMON_ASSET_TYPE value from "ASSET" to "USER", then insert the new result into My_Table.
I do not know how to write it since now I feel it is a trouble to insert records manually.
Update:
I have far more columns in table and most of them are not nullable, I want to keep all these columns' data for new records except above two columns.Is there any way if I do not have to write all these column names in sql?
Try to use NEWID if you want to create new guid:
INSERT INTO dbo.YourTable
(
COMMON_ID,
COMMON_ASSET_TYPE
)
select NEWID(), 'User' as Common_Asset_Type
from My_Table
where COMMON_ASSET_TYPE = "ASSET"
UPDATE:
As a good practice I would suggest to write all column names explicitly to have a clean and clear insert statement. However, you can use the following construction, but it is not advisable in my opinion:
insert into table_One
select
id
, isnull(name,'Jon')
from table_Two
INSERT INTO My_Table (COMMON_ID,COMMON_LIMIT_IDENTITY, COMMON_CLASS_ID,COMMON_ASSET_TYPE)
SELECT NEWID(), COMMON_LIMIT_IDENTITY, COMMON_CLASS_ID,'USER'
FROM My_Table
WHERE COMMON_ASSET_TYPE = 'ASSET'
If I've understood correctly you want to take existing records in your table, modify them, and insert them as new records in the same table.
I'll assume ID column contains the the GUID?
I'd first create a temporary table
CREATE TABLE #myTempTable(
ID UNIQUEIDENTIFIER,
Name varchar(max),
... etc
);
Fill this temp table with the records to change with your SELECT statement.
Change the records in the temp table using UPDATE statement.
Finally, Insert those "new" records back into the primary table. with INSERT INTO SELECT statement.
You will probably have to sandwitch the INSERT INTO SELECT with IDENTITY_INSERT (on/off):
SET IDENTITY_INSERT schema_name.table_name ON
SET IDENTITY_INSERT schema_name.table_name OFF
IDENTITY_INSERT "Allows explicit values to be inserted into the identity column of a table."

SQL Server Insert Into Table containing a column "Timestamp (Rowversion)"

I'm creating a C# Winforms application for recipe management in an industrial environment.
I created a SQL Server table with 130 columns. The table contains a column called CheckData (of datatype Timestamp), which I use to detect changes made to a row.
If I insert a new row to that table all works fine. The code I use is:
INSERT INTO tablename (Column1, column2, column3, column4)
VALUES (value1, value2, value3, value4)
I just assign values to major columns, the others get their default value. I do not assign a value to the timestamp field since it's written by the system.
Additionally, I want to copy a row from this table to the same table (duplicate a data record).
I copy the source row to a temporary table, drop the ID (primary key) and the timestamp fields in that temporary table and try to insert that only row in the temporary table into the table. This fails.
Here's the code:
SELECT *
INTO #temptable
FROM tablename
WHERE Recipe_No = 8;
ALTER TABLE #temptable DROP COLUMN ID, CHECKDATA;
ALTER TABLE #temptable REBUILD;
UPDATE #temptable
SET Recipe_No = 9, Recipe_Name = 'Test'
WHERE Recipe_No = 8;
INSERT INTO tablename
SELECT * FROM #temptable;
I don't understand where the difference is between inserting a new row thru INSERT INTO xxx (yyy) VALUES (zzz) and INSERT INTO xxx SELECT * FROM yyy. In both cases I don't try to write the timestamp value in the new row.
Does anybody have an idea what I'm missing here?
I don't understand where the difference is between inserting a new row thru INSERT INTO xxx (yyy) VALUES (zzz) and INSERT INTO xxx SELECT * FROM yyy.
With this,
INSERT INTO xxx SELECT * FROM yyy.
you are failing to specify the column mappings from the SELECT to the target table. You should always use
INSERT INTO xxx (Column1, Column2, . . .)
SELECT (Column1, Column2, . . .)
FROM yyy
Here's a simplified example of what you're attempting:
drop table if exists t
create table t(id int, a int)
insert into t(id,a) values (1,1)
select * into #t from t where id = 1
alter table #t drop column id
insert into t select * from #t
and it will fail with
Msg 213, Level 16, State 1, Line 12
Column name or number of supplied values does not match table definition.
because the temp table doesn't even have the same number of columns. And even if it did, you wouldn't know for sure that the column mappings were correct.
It is failing because essentially your command
INSERT INTO tablename SELECT * FROM #temptable;";
Is telling SQL - "Insert everything into this table from this temp table."
While you can work around this, I would say why don't you just try inserting into only the columns made available in your current table with only the values you would like to include. Instead of needing to drop the columns/values, you just don't import it to begin with.
An alternative - if you can write to a helper table, it may be beneficial to INSERT INTO that helper table, as opposed to a temp table, the values you have. Then transform that helper table, and THEN you can do INSERT INTO final_table SELECT * FROM helper. This should give you the results you're looking for.
I hope this is helpful, and I hope it explains why your current command is failing.

Save return values from INSERT...RETURNING into temp table (PostgreSQL)

I have a table table1 with columns id,value1 and value2.
Also I have a query
INSERT INTO table1(value1,value2) SELECT value3,value4 FROM table2 RETURNING id
that returns set of ids.
I want to store return values (these ids) in some temp table. Something like that:
INSERT INTO TEMP temp1 INSERT INTO table1(value1,value2) SELECT value3,value4 FROM table2 RETURNING id
How can I do it?
DBMS is PostgreSQL
with inserted as (
INSERT INTO table1 (value1,value2)
SELECT value3,value4
FROM table2
RETURNING id
)
insert into temp
select id
from inserted;
This requires Postgres 9.2 or later.
Two options.
If you need it just for one follow-up query, a with statement (see the horse's answer) is the easiest.
If you need it for more than one follow-up query, the other option is to not use insert ... returning, but rather create table as:
CREATE TEMPORARY TABLE foo AS
SELECT value3,value4 FROM table2
Caveats: if necessary, create the indexes you need on the table -- and analyze it if you do.

Insert Multiple Rows into Table from a Table

I have a SQL Server 2008 database. The database has a stored procedure which receives two strings as parameters. One parameter is used to build a temp table which will usually only have 1 or 2 rows but theoretically could have more.
For each row in the temp table, I need to insert a row into a different table that consists of the other parameter and the contents of the temp table. Is there a way to do this without a cursor?
I've tried variations on the following:
Pseudo code:
procedure InsertLinks(#Key varchar(36), #LinkKey varchar(36)
tempLinks Table = getLinks(#LinkKey)
Insert into MyTable (Key, LinksTo) Values (#Key, Select LinksTo From tempLinks)
The VALUES clause is messed up - you have a single value comma a table. That's not valid.
The following should work just fine:
INSERT INTO MyTable (Key, LinksTo)
SELECT #Key, LinksTo
FROM tempLinks

How can I retrieve the identities of rows that were inserted through insert...select?

I am inserting records through a query similar to this one:
insert into tbl_xyz select field1 from tbl_abc
Now I would like to retreive the newly generated IDENTITY Values of the inserted records. How do I do this with minimum amount of locking and maximum reliability?
You can get this information using the OUTPUT clause.
You can output your information to a temp target table or view.
Here's an example:
DECLARE #InsertedIDs TABLE (ID bigint)
INSERT into DestTable (col1, col2, col3, col4)
OUTPUT INSERTED.ID INTO #InsertedIDs
SELECT col1, col2, col3, col4 FROM SourceTable
You can then query the table InsertedIDs for your inserted IDs.
##IDENTITY will return you the last inserted IDENTITY value, so you have two possible problems
Beware of triggers executed when inserting into table_xyz as this may change the value of ##IDENTITY.
Does tbl_abc have more than one row. If so then ##IDENTITY will only return the identity value of the last row
Issue 1 can be resolved by using SCOPE__IDENTITY() instead of ##IDENTITY
Issue 2 is harder to resolve. Does field1 in tbl_abc define a unique record within tbl_xyz, if so you could reselect the data from table_xyz with the identity column. There are other solutions using CURSORS but these will be slow.
SELECT ##IDENTITY
This is how I've done it before. Not sure if this will meet the latter half of your post though.
EDIT
Found this link too, but not sure if it is the same...
How to insert multiple records and get the identity value?
As far as I know, you can't really do this with straight SQL in the same script. But you could create an INSERT trigger. Now, I hate triggers, but it's one way of doing it.
Depending on what you are trying to do, you might want to insert the rows into a temp table or table variable first, and deal with the result set that way. Hopefully, there is a unique column that you can link to.
You could also lock the table, get the max key, insert your rows, and then get your max key again and do a range.
Trigger:
--Use the Inserted table. This conaints all of the inserted rows.
SELECT * FROM Inserted
Temp Table:
insert field1, unique_col into #temp from tbl_abc
insert into tbl_xyz (field1, unique_col) select field1, unique_col from tbl_abc
--This could be an update, or a cursor, or whatever you want to do
SELECT * FROM tbl_xyz WHERE EXISTS (SELECT top 1 unique_col FROM #temp WHERE unique_col = tbl_xyz.unique_col)
Key Range:
Declare #minkey as int, #maxkey as int
BEGIN TRANS --You have to lock the table for this to work
--key is the name of your identity column
SELECT #minkey = MAX(key) FROM tbl_xyz
insert into tbl_xyz select field1 from tbl_abc
SELECT #maxkey = MAX(key) FROM tbl_xyz
COMMIT Trans
SELECT * FROM tbl_xyz WHERE key BETWEEN #minkey and #maxkey