I'd add a PriorShipments
field to the fact table. You'll have a lot of rows, but clustering on the ShipDate
field should be pretty efficient, and querying would be quite simple.
CREATE TABLE #Shipments
(
ID INT NOT NULL,
ShipDate DATE NOT NULL,
PRIMARY KEY (ID, ShipDate),
CustomerID INT NOT NULL,
PriorShipments INT NOT NULL DEFAULT 0
)
INSERT INTO #Shipments (ShipDate, ID, CustomerID) VALUES
('2005-08-10', 7112, 942),
('2007-07-15', 8798, 160),
('2009-04-03', 8798, 160),
('2009-04-15', 8798, 160),
('2009-04-21', 8798, 160),
('2009-04-21', 145751, 139),
('2009-04-22', 7112, 942),
('2009-04-22', 12121, 1015),
('2009-04-25', 8798, 160),
('2009-05-12', 8798, 160)
UPDATE RS
SET PriorShipments = NumPrev
FROM #Shipments AS RS
INNER JOIN
(
SELECT S1.ID, S1.ShipDate, COUNT(*) AS NumPrev
FROM #Shipments AS S1
INNER JOIN #Shipments AS S2 ON S1.ID = S2.ID AND S2.ShipDate < S1.ShipDate
GROUP BY S1.ID, S1.ShipDate
) AS Seq ON RS.ID = Seq.ID AND RS.ShipDate = Seq.ShipDate
-- If Farmer Brown gets a Dept of Agriculture grant to upgrade his database, he could instead use:
UPDATE RS
SET PriorShipments = Seq - 1
FROM #Shipments AS RS
INNER JOIN
(
SELECT ID, ShipDate, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ShipDate) AS Seq
FROM #Shipments
) AS Seq ON RS.ID = Seq.ID AND RS.ShipDate = Seq.ShipDate
-- The good part
SELECT COUNT(*) FROM #Shipments WHERE ShipDate BETWEEN '2009-04-01' AND '2009-04-30'
SELECT COUNT(*) FROM #Shipments WHERE ShipDate BETWEEN '2009-04-01' AND '2009-04-30' AND PriorShipments = 1
SELECT COUNT(*) FROM #Shipments WHERE ShipDate BETWEEN '2009-04-01' AND '2009-04-30' AND PriorShipments >= 2
You can pre-aggregate this a little, as long as Farmer Brown is never going to care about to which farms he has been shipping peaches.
Movin' to the country, gunna eat me a lot of peaches...
Best Answer
TableB
must contain only one row withTableB.TableA_Id = 0
. If not then usefiddle