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,您需要两条信息:

  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 回答