次の2つのテーブルがあります。
期日:
DECLARE @DueDates TABLE (
uniqueln varchar(10),
ship_dts smalldatetime,
qty decimal(18,4))
INSERT INTO @DueDates
SELECT '51351621AS','1/1/2013',7
UNION ALL
SELECT '51351621AS','1/7/2013',7
UNION ALL
SELECT '51351621AS','1/14/2013',7
UNION ALL
SELECT '51351621AS','1/21/2013',7
UNION ALL
SELECT '51351621AS','1/28/2013',7
UNION ALL
SELECT 'V4351621AS','1/5/2013',10
UNION ALL
SELECT 'V4351621AS','1/10/2013',10
UNION ALL
SELECT 'V4351621AS','1/15/2013',10
UNION ALL
SELECT 'V4351621AS','1/20/2013',10
UNION ALL
SELECT 'V4351621AS','1/25/2013',10
PlDetail
DECLARE @PlDetail TABLE (
uniqueln varchar(10),
shipdate smalldatetime,
shippedqty decimal(18,4))
INSERT INTO @PlDetail
SELECT '51351621AS','1/1/2013',10
UNION ALL
SELECT '51351621AS','1/7/2013',10
UNION ALL
SELECT '51351621AS','1/14/2013',10
UNION ALL
SELECT '51351621AS','1/21/2013',5
UNION ALL
SELECT 'V4351621AS','1/5/2013',13
UNION ALL
SELECT 'V4351621AS','1/15/2013',9
UNION ALL
SELECT 'V4351621AS','1/25/2013',12
UNION ALL
SELECT 'V4351621AS','1/30/2013',10
UNION ALL
SELECT 'V4351621AS','2/5/2013',6
の出荷は、テーブルPlDetail
内の注文と 1 対 1 である可能性がありますが、多くの場合、そうではありません。DueDates
uniqueln
メソッドを使用して各スケジュールの納期を計算しようとしてFIFO
います (データをテーブルに保存する方法を変更することはできません)。基本的には、一番早い発送を一番早い配達に適用したいです。
出荷数量がDueDates
記録の残高を超えた場合、その残高は次のスケジュールされた配送に適用される必要があります。
最終結果は次のようになります。
uniqueln ship_dts qty shipdate shippedqty daysLate
51351621AS 1/1/2013 7 1/1/2013 7 0
51351621AS 1/7/2013 7 1/1/2013 3 -6
51351621AS 1/7/2013 7 1/7/2013 4 0
51351621AS 1/14/2013 7 1/7/2013 6 -7
51351621AS 1/14/2013 7 1/14/2013 1 0
51351621AS 1/21/2013 7 1/14/2013 7 -7
51351621AS 1/28/2013 7 1/14/2013 2 -14
51351621AS 1/28/2013 7 1/21/2013 5 -7
V4351621AS 1/5/2013 10 1/5/2013 10 0
V4351621AS 1/10/2013 10 1/5/2013 3 -5
V4351621AS 1/10/2013 10 1/15/2013 7 5
V4351621AS 1/15/2013 10 1/15/2013 2 0
V4351621AS 1/15/2013 10 1/25/2013 8 10
V4351621AS 1/20/2013 10 1/25/2013 4 5
V4351621AS 1/20/2013 10 1/30/2013 6 10
V4351621AS 1/25/2013 10 1/30/2013 4 5
V4351621AS 1/25/2013 10 2/5/2013 6 11
PlDetail
次の期日またはそれ以前の出荷がグループ化されるように、出荷を厳密に日付別にグループ化する方法を知っていますが、予定数量と出荷数量を考慮に入れる必要があります。
カーソルを作成して出荷レコードを循環させたくはありませんが、このタイプの結合が機能しない場合は可能です。ただし、可能だと思いますが、テーブルをグループ化または結合する方法がわかりません。
SQL Server 2012 には、これを簡単にする新しい方法がいくつかあるようですが、現在、私は SQL SERVER 2008 R2 を使用しており、近い将来もそのままにしておく必要があります。
これにアプローチする最良の方法は何ですか?カーソルは本当に唯一の方法ですか?
更新: これは私がこれまでに追加したものです。最終結果は、uniqueln ごとに from と to の数量と ship_dts を示すテーブルです。
WITH DSeq AS (
SELECT TOP 100 PERCENT
Seq = Row_Number() OVER (partition by uniqueln ORDER BY ship_dts),
D.UNIQUELN,
D.SHIP_DTS,
SchBal = (SELECT TOP 100 PERCENT SUM(B.Qty) FROM @DueDates B WHERE b.SHIP_DTS<= D.SHIP_DTS AND b.UNIQUELN=d.UNIQUELN ORDER BY d.SHIP_DTS)
FROM @DueDates D
GROUP BY UNIQUELN,D.QTY,D.UNIQUELN,D.SHIP_DTS
ORDER BY D.UNIQUELN, D.SHIP_DTS
)
--SELECT * FROM DSeq
, Slices AS (
SELECT
LN = D.UNIQUELN,
FromQty = COALESCE(N.SchBal,0),
ToQty = D.SchBal,
D.SHIP_DTS
FROM
DSeq D
LEFT OUTER JOIN DSeq N
ON D.Seq -1 = N.Seq AND D.UNIQUELN=N.UNIQUELN
)
SELECT * FROM Slices
カーソルアプローチ:
すでに述べたように、最良のアプローチはカーソルかもしれません。誰かがすべてのニーズを満たす結合方法を持っていることを願っていますが、それまではカーソルを使用しています。
誰かがカーソルアプローチでこれに対する解決策を探している場合、以下のコードは私たちがそれを行った方法です. ユーザーが日付範囲を選択すると、結果が生成されます。uniqueln
選択した日付範囲より前に出荷された場合でも、のすべてのレコードに対してカーソルを実行する必要があることに注意してください。そうしないFIFO
と、出荷の適用が間違ってしまいます。
DECLARE @startdate smalldatetime, @endDate smalldatetime
DECLARE @OnTime TABLE (Uniqueln varchar(10),DueQty int,dueDate smalldatetime,shipDate smalldatetime,shipQty int DEFAULT 0,daysLate int,balQty int)
DECLARE @uniqln1 varchar(10),@toQty int, @dueDate smalldatetime,@bQty int
DECLARE @uniqln2 varchar(10),@shipQty int, @shipDate smalldatetime
DECLARE ot_cursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT uniqueln,qty,ship_dts,qty
FROM @DueDates
ORDER BY uniqueln,ship_dts
OPEN ot_cursor;
FETCH NEXT FROM ot_cursor INTO @uniqln1,@toQty,@dueDate,@bQty
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE s_cursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT Uniqueln,shippedqty,shipdate
FROM @PlDetail p
WHERE uniqueln = @uniqln1
ORDER BY 3
OPEN s_cursor ;
FETCH NEXT FROM s_cursor INTO @uniqln2,@shipQty,@shipDate
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO @OnTime(Uniqueln,DueQty,dueDate,shipDate,shipQty,daysLate,balQty)
SELECT @uniqln1,@toQty,@dueDate,@shipDate,CASE WHEN @bQty>@shipQty THEN @shipQty ELSE @bQty END,DATEDIFF(d,@dueDate,@shipDate),CASE WHEN @bQty>@shipQty THEN @bQty-@shipQty ELSE 0 END
SET @bQty=@bQty-@shipQty
IF @bQty < 0
BEGIN
SET @shipQty = -@bQty
FETCH NEXT FROM ot_cursor INTO @uniqln1,@toQty,@dueDate,@bQty
END
ELSE
IF @bQty =0
BEGIN
BREAK
END
ELSE
BEGIN
SET @shipQty = @bQty
FETCH NEXT FROM s_cursor INTO @uniqln2,@shipQty,@shipDate
END
END
CLOSE s_cursor
DEALLOCATE s_cursor
FETCH NEXT FROM ot_cursor INTO @uniqln1,@toQty,@dueDate,@bQty
END
CLOSE ot_cursor
DEALLOCATE ot_cursor
SELECT * FROM @OnTime
WHERE shipDate BETWEEN @startdate AND @endDate
ORDER BY Uniqueln,dueDate