2

私はテーブルを持っています:

PersonID    FirstName   PersonAge
1           Pras        2
2           Deep        3
3           Test        4
4           Prash       2
5           ser         1
6           df          8
7           ddf         5
8           vvv         4
9           ddd         1
10          eww         6
11          vvv         3
12          vbbb        7
13          Prabbbbs    6

グループの合計年齢が 10 を超えないようにグループ化したい。

再帰でこれを行うことができますが、大きなテーブルでは非効率的です。

  ;WITH cte AS
(
    SELECT PersonID, PersonAge, 1 AS [Group], PersonAge AS RunningTotal FROM POP where PersonId=1
    UNION ALL
    SELECT data.PersonId, data.PersonAge, 
        CASE WHEN cte.RunningTotal + data.PersonAge > 10 THEN cte.[Group] + 1 ELSE cte.[Group] END, 
        -- Reset the running total for each new group
        data.PersonAge + CASE WHEN cte.RunningTotal + data.PersonAge > 10 THEN 0 ELSE cte.RunningTotal END
    FROM POP data INNER JOIN cte ON data.PersonId = cte.PersonID + 1
)
SELECT * FROM cte

したがって、必要な出力は次のようになります。

PersonID    PersonAge   Group   RunningTotal
1           2           1       2
2           3           1       5
3           4           1       9
4           2           2       2
5           1           2       3
6           8           3       8
7           5           4       5
8           4           4       9
9           1           4       10
10          6           5       6
11          3           5       9
12          7           6       7
13          6           7       6

良い非再帰的な解決策はありますか?

編集: 試行 #1: 実行中の合計の行に沿って考えて、前の行まで CurrRunningTotal と RunningTotal を含むテーブルを取得しました。

WITH TE
AS (SELECT
  PersonId,
  FirstName,
  PersonAge,
  SUM(PersonAge) OVER (ORDER BY PersonId
  ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
  AS PrevRunningTotal,
  SUM(PersonAge) OVER (ORDER BY PersonId
  ROWS UNBOUNDED PRECEDING)
  AS RunningTotal
FROM POP),
MergedGroup
AS (SELECT
  *,
  SUM(CASE
    WHEN RunningTotal > @total THEN RunningTotal - @total
    ELSE PersonAge
  END) OVER (ORDER BY PersonId) AS Total
FROM TE)
SELECT
  *
FROM MergedGroup

私はPreviousRunningTotalを使用したい気がします。しきい値に達したときに、パディングで合計を取得するために魔法をかけることができます。つまり、しきい値を超えた場合、現在の行に10を追加して合計をオフセットします.それでも近いですが、葉巻はありません.

4

1 に答える 1

1

はい、条件を簡単に満たすことができますが、最適ではありません。でグループ化するだけpersonidです。

おそらく、「最初から開始して隣接するレコードを使用する」または「グループの数を最小限に抑える」ようなことを意図していると思われます。後者はビンパッキングの問題であり、効率的なパフォーマンスを備えた既知のアルゴリズムは存在しません。

前者は (残念ながら) 最初からデータを循環する必要があり、それが再帰 CTE の機能です。問題を解決するための他の一般的なアプローチは知りません。問題の正確な制約に応じて、特定のアプローチがある場合があります。

于 2018-05-24T19:46:14.113 に答える