Reputation: 7621
I'm currently writing an SQL statement which outputs the details of a delivery for a customer, into a nice repeater grid. However, based on a field in the customers table (with an integer determing how many rows), i need to be able to generate that many rows with the exact same details in them.
I.E: A delivery has one row, but based on the number in the customers table for that customer, the same row needs to be outputted that many times in the SQL.
Any ideas? Sorry if it's a bit confusing, and I know it sounds stupid, but from the SQL 'labels' are being generated for that delivery, and multiple labels may be required.
Upvotes: 2
Views: 334
Reputation: 1995
I think what would work well here is a recursive CTE. In my example I make table variables with some sample data that are only useful for demonstration. The part from DECLARE @RepeatedLevel = 3;
and onwards is the query itself.
-- Sample table variables are purely for demonstration.
DECLARE @Customer TABLE
(
ID INT IDENTITY(1,1)
, Name VARCHAR(25)
)
DECLARE @Delivery TABLE
(
ID INT IDENTITY(1,1)
, CustomerID INT
, DeliveryDate DATE
);
INSERT INTO @Customer
VALUES ('Jeremy'), ('Chris'), ('Sachin'), ('AdaTheDev');
INSERT INTO @Delivery
VALUES (1, '20100602')
, (2, '20100726')
, (2, '20110103')
, (3, '20090401')
, (3, '20100214')
, (3, '20100726')
, (4, '20100713')
, (4, '20100719')
, (4, '20100813')
, (4, '20101028');
DECLARE @RepeatedLevel INT = 3;
WITH DeliverysRepeated AS
(
SELECT
Customer.Name
, Delivery.DeliveryDate
, 1 AS RecursionLevel
FROM @Customer Customer
INNER JOIN @Delivery Delivery
ON Delivery.CustomerID = Customer.ID
UNION ALL
SELECT
DeliverysRepeated.Name
, DeliverysRepeated.DeliveryDate
, DeliverysRepeated.RecursionLevel + 1 AS RecursionLevel
FROM DeliverysRepeated
WHERE DeliverysRepeated.RecursionLevel < @RepeatedLevel
)
SELECT
DeliverysRepeated.Name
, DeliverysRepeated.DeliveryDate
FROM DeliverysRepeated
ORDER BY Name, DeliveryDate DESC
Upvotes: 0
Reputation: 147324
Here's one way, making use of a "Numbers" table which you can just create and populate with numbers from 1 to n (one-off process)
SELECT d.*
FROM Delivery d
JOIN Customer c ON d.CustomerID = c.ID
JOIN @Numbers n ON c.NumberField >= n.Num
e.g. basic example
DECLARE @T1 TABLE (ID INTEGER)
DECLARE @T2 TABLE (ID INTEGER, RowCnt INTEGER)
INSERT @T1 VALUES (1)
INSERT @T1 VALUES (2)
INSERT @T1 VALUES (3)
INSERT @T1 VALUES (4)
INSERT @T2 VALUES (1,1)
INSERT @T2 VALUES (2,2)
INSERT @T2 VALUES (3,4)
DECLARE @Numbers TABLE (Num INTEGER)
INSERT @Numbers VALUES(1)
INSERT @Numbers VALUES(2)
INSERT @Numbers VALUES(3)
INSERT @Numbers VALUES(4)
INSERT @Numbers VALUES(5)
SELECT t1.*
FROM @T1 t1
JOIN @T2 t2 ON t1.ID = t2.ID
JOIN @Numbers n ON t2.RowCnt >= n.Num
UPDATE
If you don't want to create a physical numbers table, you can (for numbers 1-2048) use spt_values like this:
SELECT t1.*
FROM @T1 t1
JOIN @T2 t2 ON t1.ID = t2.ID
JOIN spt_values n ON t2.RowCnt >= n.Num AND n.type='P'
Upvotes: 3
Reputation: 138990
Extended answer from AdaTheDev. Using a CTE to create the number table.
with Numbers(Num)
as
(
select 1 as Num
union all
select (Num + 1) as Num
from Numbers
where Num < 1000
)
select t1.*
from @T1 t1
join @T2 t2 on t1.ID = t2.ID
join Numbers n on t2.RowCnt >= n.Num option(maxrecursion 1000)
Upvotes: 3