while loop to insert data into table in sql - sql-server

declare #temp int,
#temp1 int,
#temp2 int,
#temp3 int,
#temp4 int,
#temp5 int,
#modid int,
#supid int,
#sid varchar(50)
begin tran
select * from StudentSupervisor;
select #temp = count(*) from Students s where s.IsLockedOut = '0' and s.IsGraduated = '0';
select #temp1 = count(*) from staffs st where st.IsLockedOut ='0';
set #temp5 = round(#temp/#temp1,0);
WHILE (select count(*) from students s where s.IsLockedOut ='0' and s.StudentId not in (select ss.StudentId from StudentSupervisor ss where s.StudentId = ss.StudentId and ss.IsApproved = 1)) != 0
BEGIN
select top 1 #sid = s.studentid from students s, StudentSupervisor ss where s.IsLockedOut ='0' and s.StudentId not in (select s.StudentId where s.StudentId = ss.StudentId and ss.IsApproved = 1);
select top 1 #supid = st.Staffid, #modid = st.moderatorid from Staffs st where st.IsLockedOut =0 and Quota <=#temp5;
insert into StudentSupervisor
(StudentId,SupervisorId,ModeratorId,IsApproved)
values
(#sid,#supid,#modid,1)
update Staffs set quota +=1 where staffs.StaffID = #supid;
END
select * from StudentSupervisor;
ROLLBACK tran
Hi all, i am quite stuck on this logic and i did search for solution but i get nothing after overnight work, let me clear with my situation now, first i would like to take count of student that not in studentsupervisor table or in studentsupervisor table but isapproved !=1, then i take the count of staff that quota is not more than total student / total staff,after that i would like to pump student together with staff into studentsupervisor table while they still available.. please let me know what wrong with my dynamic query, thanks

I am having trouble understanding your question. I think your loop condition should be:
WHILE (SELECT COUNT(*) from students WHERE StudentID NOT IN (SELECT StudentID FROM StudentSupervisor WHERE IsAppoved = 1)) <> 0
Depending on what you are trying to do in the loop, it will probably be possible to remove the loop. If you can update your question with more detail on what is happening in the loop and an example I will try to provide a more complete answer.
Update:
In that case I would also update the first line in the loop to:
select top 1 #sid = studentid from students WHERE IsLockedOut = 0 and StudentId NOT IN (SELECT StudentID FROM StudentSupervisor WHERE IsAppoved = 1);
Update2 Table variable option:
declare #temp int,
#temp1 int,
#temp2 int,
#temp5 int,
#PairCount int, --The number of students paired with a staff member.
#modid int,
#supid int,
#StaffQuotaNeed int, --The number of students the staff needs to be paired with to meet quota.
#sid varchar(50)
DECLARE #StaffToPair table
(
StaffID int NOT NULL,
ModeratorID int NOT NULL,
QuotaNeed int NOT NULL --The number of students the staff needs to be paired with to meet quota.
);
DECLARE #StudentsToPair table (StudentID int NOT NULL);
DECLARE #StudentsPaired table (StudentID int NOT NULL);
begin tran
select * from StudentSupervisor;
select #temp = count(*) from Students where IsLockedOut = '0' and IsGraduated = '0';
select #temp1 = count(*) from staffs where IsLockedOut ='0';
set #temp5 = round(#temp/#temp1 + .5, 0); --Round Up
INSERT INTO #StaffToPair (StaffID, ModeratorID, QuotaNeed)
SELECT StaffID, ModeratorID, #temp5 - Quota FROM Staffs WHERE IsLockedOut =0 AND Quota <#temp5;
INSERT INTO #StudentsToPair (StudentID)
SELECT StudentID from students WHERE IsLockedOut = 0 AND StudentId NOT IN (SELECT StudentID FROM StudentSupervisor WHERE IsAppoved = 1);
WHILE (SELECT COUNT(*) from #StudentsToPair) > 0 AND (SELECT COUNT(*) from #StaffToPair) > 0
BEGIN
SELECT TOP 1 #supid = Staffid, #modid = ModeratorID, #StaffQuotaNeed = QuotaNeed FROM #StaffToPair;
INSERT INTO StudentSupervisor (StudentID, SupervisorId, ModeratorId, IsApproved)
OUTPUT INSERTED.StudentID INTO #StudentsPaired(StudentID)
SELECT TOP (#StaffQuotaNeed) StudentID, #supid, #modid, 1 FROM #StudentsToPair;
DELETE FROM #StudentsToPair WHERE StudentID IN (SELECT StudentID FROM #StudentsPaired); --Delete paired students from table variable.
DELETE FROM #StaffToPair WHERE StaffID = #supid; --Delete paired staff from table variable.
SELECT #PairCount = COUNT(*) FROM #StudentsPaired;
UPDATE Staffs set Quota += #PairCount where staffs.StaffID = #supid;
END
select * from StudentSupervisor;
ROLLBACK tran
If the above does not work then please update your question to contain the table schema's so I can test it on my system.

Related

Update in Batches Never Finishes

as a follow up on my question original question posted here
UPDATE in Batches Does Not End and Remaining Data Does Not Get Updated
If you use the logic below you'll see that update never finishes. Let me know if you have any ideas why...
Table 1
IF OBJECT_ID('tempdb..#Table2') IS NOT NULL
BEGIN
DROP TABLE #Table2;
END
CREATE TABLE #Table2 (ID INT);
DECLARE #Count int = 0;
WHILE (select count(*) from #Table2) < 10000 BEGIN
INSERT INTO #Table2 (ID)
VALUES (#Count)
-- Make sure we have a unique id for the test, else we can't identify 10 records
set #Count = #Count + 1;
END
Table 2
IF OBJECT_ID('tempdb..#Table1') IS NOT NULL
BEGIN
DROP TABLE #Table1;
END
CREATE TABLE #Table1 (ID INT);
DECLARE #Count int = 0;
WHILE (select count(*) from #Table1) < 5000 BEGIN
INSERT INTO #Table1 (ID)
VALUES (#Count)
-- Make sure we have a unique id for the test, else we can't identify 10 records
set #Count = #Count + 1;
END
/****************** UPDATE ********************/
select count (*) from #Table2 t2 where Exists (select * from #Table1 t1 where t1.ID = t2.ID)
select count (*) from #Table2 where ID = 0
select count (*) from #Table1 where ID = 0
-- While exists an 'un-updated' record continue
WHILE exists (select 1 from #Table2 t2 where Exists (select * from #Table1 t1 where t1.ID = t2.ID) )
BEGIN
-- Update any top 10 'un-updated' records
UPDATE t2
SET ID = 0
FROM #Table2 t2
WHERE ID IN (select top 10 id from #Table2 where Exists (select * from #Table1 t1 where t1.ID = t2.ID) )
END
Your UPDATE statement is referencing the wrong instance on #Table2. You want the following:
UPDATE t2 SET
ID = 0
FROM #Table2 t2
WHERE ID IN (
SELECT TOP 10 ID
-- note this alias is t2a, and is what the `exists` needs to reference
-- not the table being updated (`t2`)
FROM #Table2 t2a
WHERE EXISTS (SELECT 1 FROM #Table1 t1 WHERE t1.ID = t2a.ID)
)
Note: For testing ensure that #Count starts from 1 not 0 else you do still end up with an infinite loop.

I need to insert rows in bulk like in 1000's using triggers having different value in one column

Here is the trigger
CREATE TRIGGER [dbo].[Teacher]
ON [dbo].[Teacher]
After INSERT
AS
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Set #Mycounter =1
While #Mycounter <5
BEGIN
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
I need to insert 1000's of rows in HeadofDep table when any row is inserted in Teacher table. I have done by applying looping but all rows that get inserted in HeadofDep table have same #PR. Need it different against each row.
Also need sessionid incremented.
How can I achieve that?
Just, increment the SessionID then and put the other stuff in the loop:
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Set #Mycounter =1
While #Mycounter <5
BEGIN
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
Also, doing such LOOPs in triggers is bad.In this case, you can change 1000 inserts with one like this:
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID + N, #fid,#PR,NULL,null
from INSERTED
CROSS APPLY
(
SELECT TOP (1000) -1+row_number() over(order by t1.number) as N
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) DS
Where eid in (Select eid from human where TypeID = 3)

Creating duplicates with a different ID for test in SQL

I have a table with 1000 unique records with one of the field as ID. For testing purpose, my requirement is that To update the last 200 records ID value to the first 200 records ID in the same table. Sequence isn't mandatory.
Appreciate help on this.
Typically I charge for doing other ppls homework, don't forget to cite your source ;)
declare #example as table (
exampleid int identity(1,1) not null
, color nvarchar(255) not null
);
insert into #example (color)
select 'black' union all
select 'green' union all
select 'purple' union all
select 'indigo' union all
select 'yellow' union all
select 'pink';
select *
from #example;
declare #max int = (select max(exampleId) from #example);
declare #min int = #max - 2
;with cte as (
select top 2 color
from #example
)
update #example
set color = a.color
from cte a
where exampleid <= #max and exampleid > #min;
select *
from #example
This script should solve the issue and will cover scenarios even if the id column is not sequential.I have included the comments to help you understand the joins and the flow of the script.
declare #test table
(
ID int not null,
Txt char(1)
)
declare #counter int = 1
/*******This variable is the top n or bottom n records in question it is 200 ,
for test purpose setting it to 20
************/
declare #delta int = 20
while(#counter <= 50)
begin
Insert into #test values(#counter * 5,CHAR(#counter+65))
set #counter = #counter + 1
end
/************Tag the records with a row id as we do not know if ID's are sequential or random ************/
Select ROW_NUMBER() over (order by ID) rownum,* into #tmp from #test
/************Logic to update the data ************/
/*Here we first do a self join on the tmp table with first 20 to last 20
then create another join to the test table based on the ID of the first 20
*/
update t
set t.ID = tid.lastID
--Select t.ID , tid.lastID
from #test t inner join
(
Select f20.rownum as first20 ,l20.rownum as last20,f20.ID as firstID, l20.ID lastID
from #tmp f20
inner join #tmp l20 on (f20.rownum + #delta) = l20.rownum
)tid on tid.firstID = t.ID and tid.first20 < = #delta
Select * from #test
drop table #tmp

MSSQL Stored Proceedure - Selecting a column by comparing values in different tables

WARNING: This is really convoluted and awful, I already know. However, I didn't build the database, I just have to work with it and I cannot change the database schema.
Here are the tables that I'm working with:
Shot
ShotID (Identity), FilmID(FK), ShotNumber, .... ,.
Tag
TagID (Identity), Name
TaggedShot
TaggedShotID (Identity), ShotID (FK), TagID(FK), TagComment
TaggedCategory
TagID (FK), CategoryID (FK)
And my stored procedure:
[dbo].[SelectAllTagNames]
#filmID int,
#tagCategory int
AS
DECLARE #i int
DECLARE #numRows int
DECLARE #ShotID int
DECLARE #TagID int
DECLARE #TagName nvarchar(50)
DECLARE #shot_table TABLE(
idx smallint Primary Key IDENTITY(1,1),
ShotID int )
DECLARE #tagID_table TABLE(
idTag smallint Primary Key IDENTITY(1,1),
TagID int)
DECLARE #tagname_table TABLE(
idTagName smallint Primary Key IDENTITY(1,1),
TagName nvarchar(50))
//get all shots in the film
INSERT #shot_table
SELECT Shot.ShotID
FROM Shot
WHERE Shot.FilmID = #filmID
//enumerate through shot table and build a tagID table of all TagIDs associated with any shot found in the shot_table
SET #i = 1
SET #numRows = (SELECT COUNT(*) FROM #shot_table)
IF #numRows > 0
BEGIN
WHILE (#i <= (SELECT MAX(idx) FROM #shot_table))
BEGIN
SET #ShotID = (SELECT ShotID FROM #shot_table WHERE idx = #i)
SET #TagID = (SELECT TaggedShot.TagID FROM TaggedShot WHERE TaggedShot.ShotID = #ShotID)
INSERT INTO #tagID_table(TagID)
VALUES(#TagID)
SET #i = #i + 1
END
END
//compare each TagID found in tagID_table with the TagID in the TaggedCategory table
// insert Tag.Name into new table if the Tag.TagID matches the TagID in the tagID_table and also matches the given tagCategory
SET #i = 1
SET #numRows = (SELECT COUNT(*) FROM #tagID_table)
IF #numRows > 0
WHILE (#i <= (SELECT MAX(idTag) FROM #tagID_table))
BEGIN
SET #TagID = (SELECT TagID FROM #tagID_table WHERE idTag = #i)
IF EXISTS(SELECT TaggedCategory.TagId FROM TaggedCategory WHERE TaggedCategory.CategoryID = #tagCategory)
BEGIN
SET #TagName = (SELECT Tag.Name FROM Tag WHERE Tag.TagId = #TagID)
INSERT INTO #tagname_table(TagName)
VALUES(#TagName)
END
END
//return all the found tag names
SELECT TagName
FROM #tagname_table
Here's what I'm trying to achieve:
Given FilmID and Tag Category ID (which is just an integer of 1, 2, or 3-- I determined this in the codebehind), I need to find all Tag.Names given those two criteria. A film is comprised of Shots.
This is not tested, but couldn't you handle what you are trying to achieve with simple joins of the tables you provided. Something like the following:
SELECT DISTINCT t.NAME
FROM Shot s
INNER JOIN TaggedShot ts ON s.ShotId = ts.ShotId
INNER JOIN Tag t ON ts.TagId = t.TagId
INNER JOIN TaggedCategory tc ON t.TagId = tc.TagId
WHERE s.FilmId = #filmId
AND tc.Categoryid = #tagCategory
UPDATE based on comment below:
SELECT t.TagId
,t.Name
FROM Tag t
WHERE t.TagId IN (
SELECT DISTINCT t.TagId
FROM Shot s
INNER JOIN TaggedShot ts ON s.ShotId = ts.ShotId
INNER JOIN Tag t ON ts.TagId = t.TagId
INNER JOIN TaggedCategory tc ON t.TagId = tc.TagId
WHERE s.FilmId = #filmId
AND tc.Categoryid = #tagCategory)

SQL simple break out by quantity

I would like to perform a simple break out by quantity in SQL.
I have as follows:
Table name : Products
product quantity
======= ========
Car 2
Bike 1
Results:
Car
Car
Bike
Thanks!
One solution is to join to a table of numbers. This can repeat the row quantity times. In T-SQL, a list of numbers can be generated with a recursive CTE:
; with Numbers as
(
select max(quantity) as nr
from YourTable
union all
select nr - 1
from Numbers
where nr > 1
)
select yt.product
from YourTable yt
join Numbers nr
on nr.nr <= yt.quantity
option (maxrecursion 0)
Live example at SQL Fiddle.
Here is a non-CTE answer to show why you should use the CTE :)
MAIN TABLE
DECLARE #table TABLE
(
ID INT IDENTITY,
Product VARCHAR(20),
Quantity INT
)
OUT TABLE
DECLARE #outtable TABLE
(
ID INT IDENTITY,
Product VARCHAR(20)
)
TEST DATA
INSERT INTO #table
(
Product,
Quantity
)
SELECT 'Car',
2
UNION ALL
SELECT 'Bike',
1
Main Query
DECLARE #counter INT,
#maxcounter INT,
#curproduct INT
SELECT TOP 1
#curproduct = id
FROM #table
WHILE EXISTS ( SELECT TOP 1
1
FROM #table
WHERE ID >= #curproduct )
BEGIN
SELECT #counter = 1,
#maxcounter = quantity
FROM #table
WHERE ID = #curproduct
WHILE #counter <= #maxcounter
BEGIN
INSERT INTO #outtable
(
Product
)
SELECT product
FROM #table
WHERE id = #curproduct
SET #counter = #counter + 1
END
SET #curproduct = #curproduct + 1
END
FINALLY
SELECT *
FROM #outtable

Resources