How to add scope_identity() to UNION ALL syntax in SQL Server - sql

I have a query for multiple inserts using UNION ALL.
How do I use SELECT scope_identity(); for each row of data inserted?
INSERT INTO MyTable (FirstCol, SecondCol)
SELECT 'First', 1
UNION ALL
SELECT 'Second', 2
UNION ALL
SELECT 'Third', 3
UNION ALL
SELECT 'Fourth', 4
UNION ALL
SELECT 'Fifth', 5

The short answer is no you can't. SCOPE_IDENTITY will give you the value of the last insert only. But you can use the OUTPUT clause from 2005 onwards. See https://msdn.microsoft.com/en-us/library/ms177564.aspx for information on how to use this clause.

You can use OUTPUT Clause to get Multiple Identity Column Value instead of scope_identity() while inserting Multiple Row.
Create Table tablename
(id int identity(1,5) Primary KEY, b int , c int)
DECLARE #tempIDs TABLE (id int)
INSERT tablename (b, c)
OUTPUT inserted.id INTO #tempIDs
SELECT 1, 1
UNION ALL
SELECT 2, 2
UNION ALL
SELECT 200, 3
UNION ALL
SELECT 3000, 4
UNION ALL
SELECT 400, 5
Select * from #tempIDs
Now your table variable #tempIDs have All Primary Key Data those are inserted using UNION ALL.

Related

SQL Server using Except vs Binary_Checksum

I am using SQL Server and want to do Bulk Updates but don't want any row to be re-updated if same values already exists.
For Example Consider following tables with their data
DECLARE #UpdatedIds TABLE
(
BookId INT
)
CREATE TABLE Book
(
[Id] INT,
[Name] NVARCHAR(MAX)
)
INSERT INTO Book([Id], [Name])
SELECT 1, 'Book1'
UNION
SELECT 2, 'Book2'
UNION
SELECT 3, 'Book3'
UNION
SELECT 4, 'Book4'
UNION
SELECT 5, 'Book5'
CREATE TABLE #Book
(
[Id] INT,
[Name] NVARCHAR(MAX)
)
INSERT INTO #Book([Id], [Name])
SELECT 1, 'Book1_Changed'
UNION
SELECT 2, 'Book2_Changed'
UNION
SELECT 3, 'Book3'
UNION
SELECT 4, 'Book4'
UNION
SELECT 5, 'Book5'
What I want is when I run the following query
UPDATE [BO]
SET [Name] = [BU].[Name]
OUTPUT [INSERTED].[Id] INTO #UpdatedIds([BookId])
FROM [Book] [BO]
INNER JOIN #Book [BU] ON [BO].[Id] = [BU].[Id]
SELECT * FROM #UpdatedIds
#UpdatedIds should have records of 1 and 2 not 3, 4, or 5
I have 2 ways of doing this in my mind and would like to have opinions about which one will be fastest/better.
Using Except Keyword and delete rows that already exists
Using Binary_Checksum that is comparing Checksums of records in actual table and in temp table and removing records with equal checksum
Thanks

By using union select for inserting values into a temp table, how to insert values in the order I assigned?

I created a temp table and inserted some values into it by using union select.
CREATE TABLE tempdb..#tempName (ID int IDENTITY (1, 1) NOT NULL, Name varchar(20) NULL)
INSERT INTO #tempName(Name)
SELECT 'tommy'
UNION SELECT 'jimmy'
UNION SELECT 'adam'
UNION SELECT 'lucy'
Problem: I want to know how to insert the value as the order I wrote. Currently it inserted in Ascending order instead.
How I want the value to be inserted:
-- ID -- Name
-- 1 -- tommy
-- 2 -- jimmy
-- 3 -- adam
-- 4 -- lucy
The Order it inserted into the temp table:
-- ID -- Name
-- 1 -- adam
-- 2 -- jimmy
-- 3 -- lucy
-- 4 -- tommy
The reason you are getting things in alphabetical order is because of the union. It does additional processing to remove duplicates. That is why union all is usually recommended.
Using union all will probably almost always do what you want:
INSERT INTO #tempName(Name)
SELECT 'tommy'
UNION ALL SELECT 'jimmy'
UNION ALL SELECT 'adam'
UNION ALL SELECT 'lucy';
This approach works in practice and seems to produce a consistent execution plan that will produce the records in order. But, this behavior is not guaranteed.
Multiple INSERTs will definitely work.
INSERT INTO #tempName(Name) SELECT 'tommy';
INSERT INTO #tempName(Name) SELECT 'jimmy'
INSERT INTO #tempName(Name) SELECT 'adam'
INSERT INTO #tempName(Name) SELECT 'lucy';
And the VALUES statement will work:
INSERT INTO #tempName(Name)
VALUES (('tommy'), ('jimmy'), ('adam'), ('lucy'));

Compare one column values for the table in sql

I have table with X number of columns. One of them is nvarchar(50). Values of this column are like this:
13-46187(IC)
13-46186(IC)
13-46189
13-46185
13-46184
I want to extract/find the highest number that the column value ends with (in this case 189). How do I accomplish that?
This is hardcoded stuff. but will give you some ideas..
create table #temp
(
textfield varchar(50)
)
insert into #temp
select '13-46187(IC)'
UNION
select '13-46186(IC)'
UNION
select '13-46189'
UNION
select '13-46185'
UNION
select '13-46184'
select Max(Convert(int,substring(SUBSTRING(textfield, 6, LEN(textfield)), 1, 3)))
from #temp

Fixed array and random numbers in an SQL query

What's the easiest way to select one of five fixed strings returned in an SQL Server query, randomly?
I.e. the equivalent of:
function randomColumn() {
var values = ['apple', 'banana', 'orange', 'cherry', 'lemon'];
var idx = Math.floor(Math.random() * 5);
return values[idx];
}
I need to change my existing SQL script to have a certain column return one of these values, without the need to change my client code.
Do I need to create a temp table?
I'm using SQL Server 2008 R2.
You don't need a temporary table for a few strings, you can create the result on the fly:
select str
from (
select 0 as id, 'apple' as str
union all
select 1, 'banana'
union all
select 2, 'orange'
union all
select 3, 'cherry'
union all
select 4, 'lemon'
) x
where id = floor(rand() * 5)
select top 1 Value
from Table1
order by newid()
SQL Fiddle Example
Select 'apple' values
INTO #tmp
UNION ALL
Select'banana' values
UNION ALL
Select 'orange' values
.
.
.
select top 1 values
from #tmp
order by newid()
OR
ALTER TABLE #tmp
ADD id BIGINT IDENTITY(1,1)
DECLARE #rand BIGINT
SET #rand=rand()*4
select top 1 values
from #tmp
where id=#rand
DECLARE #ListofIDs TABLE(IDs VARCHAR(100), ID INT IDENTITY(1,1));
INSERT INTO #ListofIDs
SELECT 'a'
UNION ALL
SELECT 'b'
UNION ALL
SELECT '20'
UNION ALL
SELECT 'c'
UNION ALL
SELECT '30'
UNION ALL
SELECT 'd';
SELECT * FROM #ListofIDs;
SELECT Ids from #ListofIDs where ID=1+ CONVERT(INT, (5)*RAND())

SQL, how can I create a lot of records for a reference join table?

At the moment, I'm using this, but its a little slow and I only end up with 1331 records. I'm thinking there must be a faster way to produce more records ?
CREATE TABLE IF NOT EXISTS util_nums (n integer primary key
autoincrement not null);
insert into util_nums values (0);
insert into util_nums(n) select null from (select 0 as n union select 1
union select 2 union select 3 union select 4 union select 5 union select 6
union select 7 union select 8 union select 9 union select 10)
a cross join (select 0 as n union select 1 union select 2 union select 3
union select 4 union select 5 union select 6 union select 7 union select 8
union select 9 union select 10) b cross join (select 0 as n union select 1
union select 2 union select 3 union select 4 union select 5 union select 6
union select 7 union select 8 union select 9 union select 10) c;
I'm using sqlite
I'm not sure if it's much faster, but you can try
--assuming table is empty, insert 2 records
insert into util_nums values (null);
insert into util_nums values (null);
insert into util_nums
select null from
util_nums,util_nums,util_nums,util_nums,util_nums,
util_nums,util_nums,util_nums,util_nums,util_nums,
util_nums,util_nums,util_nums,util_nums,util_nums,
util_nums,util_nums,util_nums,util_nums,util_nums
;
It inserts 2^20 (if you need more, just add another util_nums to from) + 2 records quite fast.
Create a file with all your data and then do a bulk insert into the table from the file.
See this
CREATE TABLE tmp_util_nums
(
n int NOT NULL,
)
go
DECLARE #SQL varchar(max)
Declare #PathFileName varchar(max)
SET #SQL = "BULK INSERT tmp_util_nums FROM '"+#PathFileName+"' WITH (FIELDTERMINATOR = ',') "
--Step 2: Execute BULK INSERT statement
EXEC (#SQL)
--Step 3: INSERT data into final table
INSERT into util_nums
SELECT * FROM tmp_util_nums
TRUNCATE TABLE tmp_util_nums
go