Loop insert SQL query - sql-server

I have the below query which returns 400 million rows. I want to run the query so it loops through and inserts 1 million records at a time. Please can I get the loop query.
insert into AST (DataAreaId, Name)
select f.DataAreaId, its.Name....... etc
from Transform.InventFin f
inner join Staging.INVENTSETTLEMENT its
on f.ITSRECID=its.RECID
and f.DataAreaId=its.DATAAREAID

Try like following(Assuming that DataAreaId is Unique, if not you need to include those columns in NOT EXISTS).
declare #Count int
set #Count = 1
while #Count > 0
begin
insert into AST (DataAreaId, Name)
select TOP (1000000) f.DataAreaId, its.Name....... etc
from Transform.InventFin f
inner join Staging.INVENTSETTLEMENT its
on f.ITSRECID=its.RECID
and f.DataAreaId=its.DATAAREAID
WHERE NOT EXISTS
(
SELECT 1 FROM AST A WHERE AST.DataAreaId = F.DataAreaId
)
set #Count = ##ROWCOUNT
end

Related

Multiple procs execution using row count in sql server

I have a proc in which I need to execute 4 different query based on the condition if the result from 1st query is 0 then it should execute the 2nd query and so on
I am using the ##RowCount to find the row count and then passing the value. Here is my code:
ALTER PROCEDURE FetchingValues #StartLocation Varchar(200),#EndLocation Varchar(200)
AS
DECLARE
#Count NUMERIC
BEGIN
if ##ROWCOUNT=0
BEGIN
select DISTINCT TOP 1 t1.Train_No,Max(t1.Distance) as TotalDistance,0 as Waiting_Time
from Rail t1
where t1.Source_Station_Name Like #StartLocation+'%'
and t1.Destination_Station_Name Like #EndLocation+'%'
GROUP BY t1.Train_No
Order BY TotalDistance ASC
SET #Count= (SELECT ##ROWCOUNT)
SELECT ##ROWCOUNT
END
ELSE if #Count <> 1
BEGIN
EXEC Connection1 #StartLocation,#EndLocation
SET #Count=(SELECT ##ROWCOUNT)
SELECT ##ROWCOUNT
END
ELSE if #Count <> 1
BEGIN
EXEC Connection2 #StartLocation,#EndLocation
SET #Count=(SELECT ##ROWCOUNT)
SELECT ##ROWCOUNT
END
ELSE
BEGIN
select DISTINCT TOP 1 (t1.Train_No+','+ t2.Train_No+','+t3.Train_No+','+t4.Train_No) as TrainSeq,
Max(t1.Distance)+Max(t2.Distance)+Max(t3.Distance)+Max(t4.Distance)as TotalDistance
from Rail t1
join Rail t2 on (t2.Source_Station_Name=t1.Destination_Station_Name)
Join Rail t3 on (t3.Source_Station_Name=t2.Destination_Station_Name)
Join Rail t4 on (t4.Source_Station_Name=t3.Destination_Station_Name)
where t1.Source_Station_Name Like #StartLocation+'%'
and t2.Destination_Station_Name Like #EndLocation+'%'
Group by t1.Train_No,T2.Train_No,t3.Train_No,t4.Train_No
ORDER BY TotalDistance ASC
END
I want to execute the query by passing 2 values then I should check through all the queries and should get the output
If you need to suppress empty resultsets then there is only one way - insert exec into temp table and check whethere there is anything or not. If there are records - no need to run next queries, just select from #.
BEGIN
select DISTINCT TOP 1 t1.Train_No,Max(t1.Distance) as TotalDistance,0 as Waiting_Time
into #t -- <<<<<<
from Rail t1
where t1.Source_Station_Name Like #StartLocation+'%'
and t1.Destination_Station_Name Like #EndLocation+'%'
GROUP BY t1.Train_No
if not exists(select 1 from #t)
BEGIN
insert #t
EXEC Connection1 #StartLocation,#EndLocation
END
if not exists(select 1 from #t)
BEGIN
insert #t
EXEC Connection2 #StartLocation,#EndLocation
END
if not exists(select 1 from #t)
...
/* finally */
select * from #t
Order BY TotalDistance ASC
END

How to set variables in While Loop in Sql Server

I am trying to use while loop instead of CURSOR in SQL SERVER. I am trying to select TOP 1 in while and set them to the variables like below. It doesnt let me set the variables in while loop. What am I doing wrong?
WHILE (
SELECT TOP 1 #WAOR_CODE = WAOR_.WAOR_CODE
, #WAOD_INVENTORYITEMID = WAOD_.WAOD_INVENTORYITEMID
FROM #wmsorder
)
BEGIN
SELECT #WAOR_CODE
, #WAOD_INVENTORYITEMID
DELETE TOP (1) #wmsorder
END
Another option:
WHILE EXISTS(select 1 FROM #wmsorder)
BEGIN
DELETE TOP (1)
FROM #wmsorder
END
However, deleting all records from a table one by one might be a performance hell. You might want to consider using TRUNCATE TABLE instead:
TRUNCATE TABLE #wmsorder
Also, note that each delete is written to the database log, while truncate table doesn't get written to the log at all.
Testing with a temporary table containing 100,000 rows, deleting the rows one by one took me 9 seconds, while truncate table completed immediately:
-- create and populate sample table
SELECT TOP 100000 IDENTITY(int,1,1) AS Number
INTO #wmsorder
FROM sys.objects s1
CROSS JOIN sys.objects s2
-- delete rows one by one
WHILE EXISTS(select 1 FROM #wmsorder)
BEGIN
DELETE TOP (1)
FROM #wmsorder
END
-- clean up
DROP TABLE #wmsorder
-- create and populate sample table
SELECT TOP 100000 IDENTITY(int,1,1) AS Number
INTO #wmsorder
FROM sys.objects s1
CROSS JOIN sys.objects s2
-- truncate the table
TRUNCATE TABLE #wmsorder
-- clean up
DROP TABLE #wmsorder
DECLARE #t TABLE (a INT PRIMARY KEY)
INSERT INTO #t
VALUES (1), (2), (3)
Variant #1:
label:
DELETE TOP(1)
FROM #t
OUTPUT DELETED.a
IF ##ROWCOUNT > 0
GOTO label
Variant #2:
WHILE ##ROWCOUNT != 0
DELETE TOP(1)
FROM #t
OUTPUT DELETED.a
Variant #3:
DECLARE #a TABLE(a INT)
WHILE ##ROWCOUNT != 0 BEGIN
DELETE FROM #a
DELETE TOP(1)
FROM #t
OUTPUT DELETED.a INTO #a
SELECT * FROM #a
END
See the below code. I just corrected the SQL statements shared by you
WHILE 1=1
BEGIN
IF NOT EXISTS (SELECT 1 FROM #wmsorder)
BREAK
SELECT TOP 1 #WAOR_CODE = WAOR_.WAOR_CODE
,#WAOD_INVENTORYITEMID = WAOD_.WAOD_INVENTORYITEMID
FROM #wmsorder WAOR_
SELECT #WAOR_CODE
,#WAOD_INVENTORYITEMID
DELETE #wmsorder WHERE WAOR_CODE = #WAOR_CODE AND WAOD_INVENTORYITEMID = #WAOD_INVENTORYITEMID
END
But as Zohar Peled mentioned, it will be a pain to the engine if you are deleting the records one by one from a table. So below I have shared another query, through this even you can track the records before deleting from the table
DECLARE #TableVar AS TABLE (WAOR_CODE VARCHAR(100), WAOD_INVENTORYITEMID VARCHAR(100))
WHILE 1=1
BEGIN
SELECT TOP 1 #WAOR_CODE = WAOR_.WAOR_CODE
,#WAOD_INVENTORYITEMID = WAOD_.WAOD_INVENTORYITEMID
FROM #wmsorder WAOR_
WHERE NOT EXISTS (SELECT 1 FROM #TableVar t WHERE t.WAOR_CODE = WAOR_.WAOR_CODE AND t.WAOD_INVENTORYITEMID = WAOR_.WAOD_INVENTORYITEMID)
IF #WAOR_CODE IS NULL AND #WAOD_INVENTORYITEMID IS NULL
BREAK
INSERT INTO #TableVar
(WAOR_CODE, WAOD_INVENTORYITEMID)
SELECT #WAOR_CODE
,#WAOD_INVENTORYITEMID
END
DELETE #wmsorder WHERE EXISTS (SELECT 1 FROM #TableVar t WHERE t.WAOR_CODE = #wmsorder.WAOR_CODE AND t.WAOD_INVENTORYITEMID = #wmsorder.WAOD_INVENTORYITEMID)
Sorry I did not test the second code. Please forgive me if it breaks something. But I am pretty sure it may require a small repair to make this query functional. All the best.

Using while loop in sql

I am trying to loop through my records with a where clause.
I am trying to get only top 100 rows first and then next 100 (some logic i apply with what i get in the select clause)
But, if the first 100 rows does not return a result, it does not goes into 2nd 100 set of data.
My query is :
DECLARE #BatchSize INT = 100
DECLARE #Counter INT = 0
DECLARE #TableCount INT = 0
set #TableCount = (select count(*) from Table1) //#TableCount = 10000
while #Counter < #TableCount/#BatchSize //#Counter < 100
BEGIN
SET #Counter=#Counter+1
INSERT INTO Table4
SELECT TOP(#BatchSize) * FROM Table2
WHERE NOT EXISTS (SELECT * Table3) and some condition
Here, If i dont get the data for first 100 rows, it wont go to next 100 set of data.
What should I do ?
Instead of TOP #BatchSize in the SELECT clause, try OFFSET #BatchSize * #Counter FETCH NEXT #Batchsize ROWS ONLY after the WHERE clause.
Based on comments, you may also want to look into a SELECT INTO query, as well as the nolock query hint.

Generate a repetitive sequential number using SQL Server 2008

Can anyone help me to generate a repetitive sequential number using SQL Server 2008. Say I have a table of 1000 rows and a new field (int) added to the table. All I need is to auto fill that particular field with sequential numbers 1-100 all the way to the last row.
I have this but doesnt seem that it is working. You help is much appreciated.
DECLARE #id INT
SET #id = 0
while #id < 101
BEGIN
UPDATE Names SET id=#id
set #id=#id+1
END
USE tempdb
GO
DROP TABLE tableof1000rows
GO
CREATE TABLE tableof1000rows (id int identity(1,1), nb int, value varchar(128))
GO
INSERT INTO tableof1000rows (value)
SELECT TOP 1000 o1.name
FROM sys.objects o1
CROSS JOIN sys.objects o2
GO
UPDATE t1
SET nb = t2.nb
FROM tableof1000rows t1
JOIN (SELECT id, (ROW_NUMBER() OVER (ORDER BY id) % 100) + 1 as nb FROM tableof1000rows) t2 ON t1.id = t2.id
GO
SELECT *
FROM tableof1000rows
Use ROW_NUMBER to generate a number. Use modulo maths to get values from 1 to 100.
go
create table dbo.Demo1
(
DID int not null identity primary key,
RepetitiveSequentialNumber int not null
) ;
go
insert into dbo.Demo1 values ( 0 )
go 1000 -- This is just to get 1,000 rows into the table.
-- Get a sequential number.
select DID, row_number() over ( order by DID ) as RSN
into #RowNumbers
from dbo.Demo1 ;
-- Take the last two digits. This gives us values from 0 to 99.
update #RowNumbers
set RSN = RSN % 100 ;
-- Change the 0 values to 100.
update #RowNumbers
set RSN = case when RSN = 0 then 100 else RSN end ;
-- Update the main table.
update dbo.Demo1
set RepetitiveSequentialNumber = r.RSN
from dbo.Demo1 as d inner join #RowNumbers as r on r.DID = d.DID ;
select *
from dbo.Demo1 ;
Not pretty or elegant, but..
while exists(select * from tbl where new_col is null)
update top(1) tbl
set new_col=(select ISNULL(max(new_col),0)+1 from tbl WHERE new_col is null)
Your way isn't working because you are trying to set a value rather than insert one. I'm sure you have found a solution by now but if not then try this instead.
DECLARE #id INT
SET #id = 0
while #id < 101
BEGIN
INSERT Names select #id
set #id=#id+1
END

Checking if something has changed in a trigger

I have a need to monitor a subset of fields on a table and perform a task when one of them changes.
I am using a trigger on the table update which and then am looking at the changes as follows:
-- join the deleted and inserted to get a full list of rows
select * into #tmp from (select * from inserted union select * from deleted) un
-- select a count of differing rows, > 1 means something is different
select distinct count(*) from #tmp
This is fine and a count of 2 or more means something is different on single line updates. Issue is if I am doing a multiple line update then this breaks down.
Is there a way I can get this to work for a multi line update or do I need to try a different approach completely.
You could do something like this (syntax completely untested)
IF NOT UPDATE(col)
RETURN
SELECT inserted.key, inserted.col as i_col, deleted.col as d_col
INTO #interestingrows
FROM inserted JOIN deleted on inserted.key = deleted.key
and inserted.col <> deleted.col /*If col is nullable cater for that as well*/
IF ##ROWCOUNT=0
RETURN
/*Process contents of #interestingrows*/
I ended up with a fairly simple solution. I wrote an additional loop around the check that did the check per line in inserted.
-- get a list of updated line id's
select field1 as id into #loop from inserted
-- loop through all the id's and do a compare
while (select count(*) from #loop) > 0 begin
select top 1 #id = id from #loop
select * into #tmp from (select * from inserted where field1 = #id union
select * from deleted where field1 = #id) un
-- do a select ditinct to count the differing lines.
if (select distinct count(*) from #tmp) > 1 begin
-- the 2 lines don't match, so mark for update
update test1 set flag = 1 where field1 = #id
end
drop table #tmp
delete #loop where id = #id
end

Resources