Insert multiple rows into SQL Server - sql-server-2005

I have two tables
Product (product_id, productName)
ProductSerialNumber (ProductSerialNumber_id, product_id, serialNumber, status)
I have serial numbers 12345679000 to 123456790100 (quantity: 90) for product : MILK
Is there way to do this without using multiple inserts ie
$Sn = 12345679000;
while ($Sn <= 123456790100 )
{
INSERT INTO ProductSerialNumber VALUES(...,...,$Sn,...)
$Sn++;
}

You can do this:
WITH Temp
AS
(
SELECT n
FROM(VALUES(0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) AS Temp(n)
), nums
AS
(
SELECT id = t1.n * 10 + t2.n + 1
FROM temp AS T1
CROSS JOIN temp AS t2
)
INSERT INTO ProductSerialNumber(serialnumber)
SELECT 12345679000 + id AS Serialnumber -- You can insert into other columns too
FROM nums;
SQL Fiddle Demo.
Note that: This syntax FROM(VALUES(0), (1), ..., (9)) AS Temp(n) is new to SQL Server-2008, for old versions you can use SELECT ... UNION ALL SELECT ... instead.
However, if possible, you can alter this table and make this column SerialNumber an IDENTITY(12345679000, 1) and it will be auto incremental.
Update 1
For SQL Server 2005, try this:
WITH Temp
AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
), nums
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY t1.id) AS id
FROM temp t1, temp t2, temp t3, temp t4
)
INSERT INTO ProductSerialNumber(serialnumber)
SELECT 12345679000 + id AS Serialnumber
FROM nums
WHERE id <= 100;
Updated SQL Fiddle Demo.
Update 2
*How does this query work? *
Firstly, I define a virtual table with only four values:
SELECT 1 AS id
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
I defined it inside a Common table expression(CTE), to reuse it later.
Then in the following CTE, I used:
FROM temp t1, temp t2, temp t3, temp t4
This will join the table temp four times with it self, therefore it will give you: 44 = 256 rows. Then I used the ranking function ROW_NUMBER() as a work a round to generate a sequence number of number from 1 to 265.
The last thing is the syntax of INSERT INTO ... SELECT ... to select the numbers <= 100 of the numbers that we already generated from the previous step and inserting them to the table.
Hope this makes sense.

here another method to insert multiple rows with procedure
CREATE PROCEDURE autoInsert
#SerialNumberStart bigint,
#SerialNumberEnd bigint,
#status int,
#productID int
AS
while #SerialNumberStart <= #SerialNumberEnd
begin
BEGIN TRAN
INSERT INTO ProductSerialNumber VALUES(#SerialNumberStart)
--print #SerialNumberStart
COMMIT TRAN;
set #SerialNumberStart=#SerialNumberStart+ 1
end

Related

Find missing numbers in a sequence in MS SQL

Say i have a table with an integer column Id. I need to find the missing numbers in a sequence with a maximum returned amount.
If the table is empty and i'm asking for 10, it should return the numbers 1-10.
If the table has 1-5 and i'm asking for 10, it should return the numbers 6,7,8,9,10,11,12,13,14,15.
If the table has 1,2,4,6,9 and im asking for 10, it should return the numbers 3,5,7,8,10,11,12,13,14,15
How can i achive this in one single query using MS SQL?
Thanks in advance!
Try this:
If you need to get more numbers, just increase the WHERE Number<=100.
DECLARE #Tab1 TABLE (ID INT)
INSERT INTO #Tab1 VALUES(1)
INSERT INTO #Tab1 VALUES(3)
INSERT INTO #Tab1 VALUES(5)
INSERT INTO #Tab1 VALUES(7)
INSERT INTO #Tab1 VALUES(9)
;WITH CTE AS
(
SELECT 1 AS Number
UNION ALL
SELECT Number + 1 FROM CTE
WHERE Number<=100
)
SELECT TOP 5 *
FROM CTE
WHERE Number NOT IN(SELECT ID FROM #Tab1)
ORDER BY Number
OPTION (maxrecursion 0);
Existing values:
Number
1
3
5
7
9
OutPut:
Number
2
4
6
8
10
Hope this helps you.
This should work
There are also a system table with numbers
declare #T table (i int primary key);
insert into #T values (1), (2), (4), (6), (9);
declare #count int = 10;
declare #size int = (select count(*) from #T);
with cte as
( select 1 as num
union all
select num + 1
from cte
where num + 1 <= (#count + #size)
)
select top (#count) cte.num
from cte
left join #T t
on t.i = cte.num
where t.i is null
order by cte.num
option ( MaxRecursion 0 );

Is it possible to multiply the results of two select statements?

If I have a select statement like this...
SELECT col1 FROM table WHERE col2=1
Which returns the results 1,2,3,4,5.
And another select statement like this...
SELECT col1 FROM table WHERE col2=2
Which return the results 6,7,8,9,10.
Is there a way to multiply the results of these two queries, so that a final result set of 6,14,24,36,50 is returned?
I've tried simple things like this.
SELECT (SELECT col1 FROM table WHERE col2=1) * (SELECT col1 FROM table WHERE col2=2)
But that didn't seem to work.
If it makes a difference, I'm using Sqlite, and the value types are REAL not INTEGER.
DECLARE #Table1 TABLE ( thing real)
DECLARE #Table2 TABLE (anotherThing real)
INSERT #Table1 (thing)
VALUES (1), (2), (3), (4), (5)
INSERT #Table2 (anotherThing)
VALUES (6), (7), (8), (9), (10)
;
SELECT T.thing * TT.anotherThing AS Multi
FROM (
SELECT T.thing
, (
SELECT COUNT(1) RN
FROM #Table1 AS T2
WHERE T2.thing <= T.Thing
) RN
FROM #Table1 AS T
)AS T
INNER JOIN (
SELECT TT.anotherThing
, (
SELECT COUNT(1) RN
FROM #Table2 AS T2
WHERE T2.anotherThing <= TT.anotherThing
) RN
FROM #Table2 AS TT
) TT
ON TT.RN = T.RN
Result:
+-------+
| Multi |
+-------+
| 6 |
| 14 |
| 24 |
| 36 |
| 50 |
+-------+
The example probably won't work in sqlite, I wrote it in sql server. This shows it works on sqlite.

Find missing numbers with SQL

In a large log file I have records containing the field INVNO (invoice-number).
The lowest and highest values are easy to find, BUT it looks like some numbers in between are not there.
Anyone got a trick with SQL, which can tell which numbers are missing within the number range?
use the following table valued function that takes 2 parameters : the min and max numbers,
and returns a list of missing number,
suppose your table name is YOUR_TABLE and the column name called InvNo
create FUNCTION [dbo].[MissingInvoiceNumbers]
(
#minPaym bigint,
#MaxPaym bigint
)
RETURNS #tmp table(numbers bigint)
AS
BEGIN
declare #n bigint --#minPaym bigint , #MaxPaym bigint,
declare #tmpAll table(Allnumbers bigint)
set #n= #minPaym
delete #tmp
delete #tmpAll
while (#n<=#MaxPaym)
begin
INSERT INTO #tmpAll
(AllNUMBERS)
VALUES (#n)
set #n=#n+1
end
INSERT INTO #tmp
(numbers)
SELECT Allnumbers
FROM #tmpAll
where Allnumbers not in (select distinct convert(bigint,InvNo) as InvoiceNum from YOUR_TABLE where
InvNo <> '' )
return
END
For oracle this should work. For any other database you just need to change way to generate the number sequence.
with vals as (
select rownum r
from dual
connect by rownum between {min} and {max}
)
select *
from vals v
left join {sometable} s on s.{someid} = v.r
where s.{someid} is null
The trick is just to generate numbers between min and max value, join table with invoices to this generated sequence and filter out everything that match.
Just join the table on itself...
DECLARE #tvp TABLE ( INVNO INT )
INSERT INTO #tvp
VALUES ( 1 ),
( 2 ),
( 3 ),
( 5 ),
( 6 ),
( 7 ),
( 8 ),
( 9 ),
( 10 ),
( 11 )
SELECT *
FROM #tvp;
SELECT t.INVNO + 1
FROM #tvp t
LEFT OUTER JOIN #tvp x ON x.INVNO = t.INVNO + 1
WHERE ISNULL(x.INVNO, 0) = 0;

Find missing numbers in a column

I have this column in T-SQL:
1
2
3
7
10
have SQl a function for detect the missing numbers in the sequence 4,5,6 and 8,9
I have try
something like
if ( a-b >1 ) then we have a missing number
with coalesce but i dont understand .
Thanks by any orientation
You can try this:
DELCARE #a
SET #a = SELECT MIN(number) FROM table
WHILE (SELECT MAX(number) FROM table ) > #a
BEGIN
IF #a NOT IN ( SELECT number FROM table )
PRINT #a
SET #a=#a+1
END
The following query will identify where each sequence starts and the number that are missing:
select t.col + 1 as MissingStart, (nextval - col - 1) as MissingSequenceLength
from (select t.col,
(select min(t.col) from t t2 where t2.col > t.col) as nextval
from t
) t
where nextval - col > 1
This is using a correlated subquery to get the next value in the table.
I know this is a late answer, but here is a query that uses recursive table expressions to get the missing values between the minimum and maximum values in a table:
WITH CTE AS
(
--This is called once to get the minimum and maximum values
SELECT nMin = MIN(t.ID), MAX(t.ID) as 'nMax'
FROM Test t
UNION ALL
--This is called multiple times until the condition is met
SELECT nMin + 1, nMax
FROM CTE
WHERE nMin < nMax
)
--Retrieves all the missing values in the table.
SELECT c.nMin
FROM CTE c
WHERE NOT EXISTS
(
SELECT ID
FROM Test
WHERE c.nMin = ID
)
This was tested with the following schema:
CREATE TABLE Test
(
ID int NOT NULL
)
INSERT INTO Test
Values(1)
INSERT INTO Test
Values(2)
INSERT INTO Test
Values(3)
INSERT INTO Test
Values(7)
INSERT INTO Test
Values(10)

Union temporary tables to a final temporary table

I have like 10 diff temporary tables created in SQL server, what I am looking to do is union them all to a final temporary table holding them all on one table. All the tables have only one row and look pretty much exactly like the two temp tables below.
Here is what I have so far this is an example of just two of the temp tables as their all exactly like this one then #final is the table I want to union the all to:
create table #lo
(
mnbr bigint
)
insert into #login (mnbr)
select distinct (_ID)
FROM [KDB].[am_LOGS].[dbo].[_LOG]
WHERE time >= '2012-7-26 9:00:00
Select count(*) as countreject
from #lo
create table #pffblo
(
mber_br
)
insert into #pffblo (mber_br)
select distinct (mber_br)
from individ ip with (nolock)
join memb mp with (nolock)
on( ip.i_id=mp.i_id and mp.p_type=101)
where ip.times >= '2012-9-26 11:00:00.000'
select count(*) as countaccept
create table #final
(
countreject bigint
, Countacceptbigint
.....
)
insert into #final (Countreject, Countaccept....more rows here...)
select Countreject, Countaccept, ...more rows selected from temp tables.
from #final
union
(select * from #lo)
union
(select * from #pffblo)
select *
from #final
drop table #lo
drop table #pffblo
drop table #final
if this the form to union the rows form those temp tables to this final one. Then is this correct way to show all those rows that were thus unioned. When I do this union I get message number of columns in union need to match number of columns selected in union
I think you're using a union the wrong way. A union is used when you have to datasets that are the same structure and you want to put them into one dataset.
e.g.:
CREATE TABLE #Table1
(
col1 BIGINT
)
CREATE TABLE #Table2
(
col1 BIGINT
)
--populate the temporary tables
CREATE TABLE #Final
(
col1 BIGINT
)
INSERT INTO #Final (col1)
SELECT *
FROM #Table1
UNION
SELECT *
FROM #Table2
drop table #table1
drop table #table2
drop table #Final
I think what you're trying to do is get 1 data set with the count of all your tables in it. Union won't do this.
The easiest way (although not very performant) would be to do select statements like the following:
CREATE TABLE #Table1
(
col1 BIGINT
)
CREATE TABLE #Table2
(
col1 BIGINT
)
--populate the temporary tables
CREATE TABLE #Final
(
col1 BIGINT,
col2 BIGINT
)
INSERT INTO #Final (col1, col2)
select (SELECT Count(*) FROM #Table1) as a, (SELECT Count(*) FROM #Table2) as b
select * From #Final
drop table #table1
drop table #table2
drop table #Final
It appears that you want to take the values from each of temp tables and then place then into a single row of data. This is basically a PIVOT, you can use something like this:
create table #final
(
countreject bigint
, Countaccept bigint
.....
)
insert into #final (Countreject, Countaccept....more rows here...)
select
from
(
select count(*) value, 'Countreject' col -- your UNION ALL's here
from #lo
union all
select count(*) value, 'countaccept' col
from #pffblo
) x
pivot
(
max(value)
for col in ([Countreject], [countaccept])
) p
Explanation:
You will create a subquery similar to this that will contain the COUNT for each of your individual temp table. There are two columns in the subquery, one column contains the count(*) from the table and the other column is the name of the alias:
select count(*) value, 'Countreject' col
from #lo
union all
select count(*) value, 'countaccept' col
from #pffblo
You then PIVOT these values to insert into your final temp table.
If you do not want to use PIVOT, then you can use a CASE statement with an aggregate function:
insert into #final (Countreject, Countaccept....more rows here...)
select max(case when col = 'Countreject' then value end) Countreject,
max(case when col = 'countaccept' then value end) countaccept
from
(
select count(*) value, 'Countreject' col -- your UNION ALL's here
from #lo
union all
select count(*) value, 'countaccept' col
from #pffblo
) x
Or you might be able to JOIN all of the temp tables similar to this, where you create a row_number() for the one record in the table and then you join the tables with the row_number():
insert into #final (Countreject, Countaccept....more rows here...)
select isnull(lo.Countreject, 0) Countreject,
isnull(pffblo.Countaccept, 0) Countaccept
from
(
select count(*) Countreject,
row_number() over(order by (SELECT 0)) rn
from #lo
) lo
left join
(
select count(*) Countaccept,
row_number() over(order by (SELECT 0)) rn
from #pffblo
) pffblo
on lo.rn = pffblo.rn
SELECT *
INTO #1
FROM TABLE2
UNION
SELECT *
FROM TABLE3
UNION
SELECT *
FROM TABLE4
If you would like to get count for each temporary table in the resulting table, you will need just to calculate it for each column in subquery:
INSERT INTO result (col1, col2,...
SELECT
(SELECT COUNT() FROM tbl1) col1
,(SELECT COUNT() FROM tbl2) col2
..