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
Related
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)
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
I have declared 6 variables in a stored procedure and I'd like to store a query result (which may bring up to 6 records) into each one of those variables. My query looks like this:
DECLARE
#Sib1 varchar(20),
#Sib2 varchar(20),
#Sib3 varchar(20),
#Sib4 varchar(20),
#Sib5 varchar(20),
#Sib6 varchar(20)
select
PC.SKU
from
Product PC
where
Parent_code in (select
Parent_code
from
Product
where
SKU =12345)
and ParentFlag <> 'p'
and SKU <> 12345
order by Parent_Child_Priority desc
I'd like to put each one of the resulting SKU in each #SIB variables. if it only returns 1 result, I'd like to put null values into the rest of the #SIB variables.
Thanks.
You could insert the SKU's into a table variable, with an identity column. Then set the variables equal to the sku in the table based on the identity columns value.
DECLARE #Sib1 VARCHAR(20)
,#Sib2 VARCHAR(20)
,#Sib3 VARCHAR(20)
,#Sib4 VARCHAR(20)
,#Sib5 VARCHAR(20)
,#Sib6 VARCHAR(20);
DECLARE #TempTbl TABLE (
RowID INT IDENTITY
,SKU VARCHAR(20)
)
INSERT INTO #TempTbl (SKU)
select
PC.SKU
from
Product PC
where
Parent_code in (select
Parent_code
from
Product
where
SKU =12345)
and ParentFlag <> 'p'
and SKU <> 12345
order by Parent_Child_Priority desc
SELECT #Sib1 = SKU
FROM #TempTbl
WHERE RowID = 1;
SELECT #Sib2 = SKU
FROM #TempTbl
WHERE RowID = 2;
SELECT #Sib3 = SKU
FROM #TempTbl
WHERE RowID = 3;
SELECT #Sib4 = SKU
FROM #TempTbl
WHERE RowID = 4;
SELECT #Sib5 = SKU
FROM #TempTbl
WHERE RowID = 5;
SELECT #Sib6 = SKU
FROM #TempTbl
WHERE RowID = 6;
EDIT
DECLARE #SQL VARCHAR(MAX);
SET #SQL = 'SELECT SKU, ..., sum(convert(INT, a.qty)) AS ' + #sib1 + ' FROM ...'
EXEC (#SQL);
Rather use a table variable like
DECLARE #MyTableVar table(
SKU int NOT NULL);
Then insert into it
insert into #MyTableVar(SKU)
select
PC.SKU
from
Product PC
where
Parent_code in (select
Parent_code
from
Product
where
SKU =12345)
and ParentFlag <> 'p'
and SKU <> 12345
order by Parent_Child_Priority desc;
Now you can use that #MyTableVar as you need. You don't need to declare N variable for N records.
The following code is close to doing what I need EXCEPT I should generate columns (p1,p2,p3...) dynamically AND I can't use pivot (see SQL Transpose rows to columns (group by key variable)).
What I am using now in SQL Server 2008:
Select InvoiceNum,
Max(Case when seq =0 Then product_Description end) as p1,
Max(Case when seq =1 Then product_Description end) as p2
From
( Select InvoiceNum, Product_Description,
Row_Number() Over(Partition by InvoiceNum
Order by InvoiceNum) - 1 seq
From #tmpTable
)d
Group by InvoiceNum
Thank you StackOverFlow Community!!
I think, like the comments also say, you should use Dynamic SQL with a PIVOT table. It can probably be done more efficiently than this.
Create the table and put some data in it:
create table invoiceTable (
InvoiceNum int,
Product_Description nvarchar(20)
)
insert into invoiceTable values (1, 'inv1 row 1'),(1, 'inv1 row 2'),(1, 'inv1 row 3'),(2, 'inv2 row 1'),(2, 'inv2 row 2')
declare the necessary variables
declare #maxNo int
declare #query nvarchar(max)
declare #i int = 0
find the max row number:
select #maxNo = max(seq) from
(
Select
InvoiceNum
,Product_Description
,Row_Number() Over(Partition by InvoiceNum Order by InvoiceNum) - 1 seq
From
invoiceTable
) maxRowNo
Build the dynamic query
set #query =
'
Select
*
From
(
Select
InvoiceNum
,Product_Description
,Row_Number() Over(Partition by InvoiceNum Order by InvoiceNum) - 1 seq
From
invoiceTable
) d
pivot
(
min(Product_Description)
for seq in (
'
while (#i <= #maxNo)
begin
if (#i > 0) set #Query += ','
set #query += '['+CAST(#i as nvarchar)+']'
set #i += 1;
end
set #query +=
')
) pvt
'
Execute the query
exec sp_executesql #query
This gives the following resultset:
InvoiceNum 0 1 2
1 inv1 row 1 inv1 row 2 inv1 row 3
2 inv2 row 1 inv2 row 2 NULL
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.