0

次のようなカードのテーブルと(カード上の)動きのテー​​ブルがあります。

declare @cards table
(
    id_card int,
    cycle int
)

insert into @cards (id_card, cycle) values (1, 10)

declare @moves table
(
    id_move int,
    id_card int,
    quantity int
)

insert into @moves (id_move, id_card, quantity) values (1, 1, 2)
insert into @moves (id_move, id_card, quantity) values (2, 1, 4)
insert into @moves (id_move, id_card, quantity) values (3, 1, 2)
insert into @moves (id_move, id_card, quantity) values (4, 1, 8)
insert into @moves (id_move, id_card, quantity) values (5, 1, 2)

問題: 各カードにはサイクル サイズがあり、各移動には数量があります。したがって、カード サイクル サイズ 10 と 18 の移動は、1 つのフル サイクルに加えて 8 移動を意味します。最後のサイクルの最初の移動 (この例では移動 ID 4) を見つける必要があります。この問題は (最初は) 些細なことのように思えますが、動きを見つけるのに非常に多くのトラブルが発生しているため、何か非常に間違ったことをしていると思います。

最後のサイクルの最初の動きの開始位置を示すクエリを思いつきましたが、そこからどこにも行けません。

select
    id_card,
    case
        when value > quantity then value - quantity
        else value
    end value
from
(
    select
        f.id_card,
        f.quantity,
        f.quantity - f.quantity % cards.cycle + 1 value
    from
    (
        select
            id_card,
            sum(quantity) quantity
        from @moves
        group by
            id_card
    ) f
    join @cards cards on
        cards.id_card = f.id_card
) f

期待される出力:

id_move
4

何か案は?問題を簡単にするために変更を加えることができます。

4

3 に答える 3

2

これはどう:

;WITH CycleCountCTE AS (
SELECT m.id_move, m.id_card, (select sum(quantity)-1 FROM @moves m2 WHERE m2.id_card = m.id_card AND m2.id_move<=m.id_move)/c.cycle + 1 AS CycleNum, 
    (SELECT MAX(m3.id_move) FROM @moves m3 WHERE m3.id_card = m.id_card AND m3.id_move < m.id_move) AS Prev_id_move
FROM @cards c
JOIN @moves m on m.id_card = c.id_card
)
SELECT cn.id_card, MAX(cn.id_move) as First_id_move_of_last_cycle
FROM CycleCountCTE cn
LEFT OUTER JOIN CycleCountCTE cp ON cp.id_move = cn.Prev_id_move
where cn.CycleNum > isnull(cp.CycleNum,0)
GROUP BY cn.id_card

またはもう少し単純です:

;WITH CycleCountCTE AS (
SELECT m.id_move, m.id_card, (select sum(quantity)-1 FROM @moves m2 WHERE m2.id_card = m.id_card AND m2.id_move<=m.id_move)/c.cycle + 1 AS CycleNum
FROM @cards c
JOIN @moves m on m.id_card = c.id_card
)
SELECT id_card, MIN(id_move) as First_id_move_of_last_cycle
FROM CycleCountCTE c
WHERE CycleNum = (SELECT MAX(CycleNum) from CycleCountCTE c2 WHERE c2.id_card = c.id_card)
GROUP BY id_card
于 2012-09-11T19:49:24.437 に答える
1

これを実行してみてください。あなたが探しているものかもしれません。カードの数量の現在の合計を取得し、そのサイクルの残りを current_cycle として返します。

SELECT 
    m.[id_move],
    m.[id_card],
    m.[quantity],
    c.[cycle],
    running_total_set.[total_quantity],
    running_total_set.[total_quantity] % c.[cycle] AS [current_cycle]
FROM @moves m
INNER JOIN @cards c
    ON m.[id_card] = c.[id_card]
INNER JOIN
(
    SELECT
        id_move_2 AS [id_move],
        SUM([quantity]) AS [total_quantity]
    FROM
    (
        SELECT
            moves1.id_move AS [id_move_1],
            moves2.id_move AS [id_move_2],
            moves1.quantity AS [quantity]
        FROM @moves moves1
        INNER JOIN @moves moves2
            ON moves2.[id_move] >= moves1.[id_move]
    )move_set
    GROUP BY [id_move_2]
)running_total_set
ON m.[id_move] = running_total_set.[id_move]
于 2012-09-11T19:25:35.137 に答える
1

個人的には、前の移動の総数を記録するセカンダリ移動テーブルを設定することから始めます。

SELECT this.id_move, this.id_card, this.quantity,
  [sumPrevMoves] = sum(prev.quantity),
  [sumMovesNow] = this.quantity + isnull(sum(prev.quantity), 0)
FROM @moves this
  LEFT JOIN @moves prev on this.id_card = prev.id_card
                       and this.id_move > prev.id_move
GROUP BY this.id_move, this.id_card, this.quantity

次に、 @cards テーブルへの単純な結合により、あらゆる種類の便利なものを見つけることができます。

SELECT m.id_move, m.id_card,
  [cardCycles] = c.cycle,
  [thisMove] = m.quantity,
  m.sumPrevMoves, m.sumMovesNow,
  [totalCycles] = m.sumMovesNow / cycle,
  [totalMoves] = m.sumMovesNow % cycle
FROM @cards c
  JOIN (/*query from above*/) m on c.id_card = m.id_card

ここから を見つけるにはlast cycle, first move、次の 2 つの情報が必要です。

  1. 最終サイクル数はいくつでしたか
  2. そのサイクルの最小移動は何でしたか

すべてをいくつかの CTE と組み合わせると、次のようにすると、必要なものが得られます。

;WITH moves2 as (
    SELECT this.id_move, this.id_card, this.quantity,
      [sumPrevMoves] = sum(prev.quantity),
      [sumMovesNow] = this.quantity + isnull(sum(prev.quantity), 0)
    FROM @moves this
      LEFT JOIN @moves prev on this.id_card = prev.id_card
                           and this.id_move > prev.id_move
    GROUP BY this.id_move, this.id_card, this.quantity
), allMoves as (
    SELECT m.id_move, m.id_card,
      [cardCycles] = c.cycle,
      [thisMove] = m.quantity,
      m.sumPrevMoves, m.sumMovesNow,
      [totalCycles] = m.sumMovesNow / cycle,
      [totalMoves] = m.sumMovesNow % cycle
    FROM @cards c
      JOIN moves2 m on c.id_card = m.id_card
)
SELECT am1.id_card, [firstMoveLastCycle] = min(am1.id_move)
FROM allMoves am1
    join (
        SELECT id_card, [lastCycle] = max(totalCycles)
        FROM allMoves
        GROUP BY id_card
    ) am2 on am1.id_card=am2.id_card
        and am1.totalCycles = am2.lastCycle
GROUP BY am1.id_card
于 2012-09-11T20:23:28.180 に答える