SQL "重み"によるレコードの順序付け

テーブルに「優先」番号でレコードを処理するシステムがあります。優先度は、表の内容で定義します。

UPDATE table
SET priority=3
WHERE processed IS NULL

UPDATE table
SET priority=2
WHERE balance>50

UPDATE table
SET priority=1
WHERE value='blah'

(優先順位の間に「重複」があるかもしれないという事実を無視してください:))

これはうまくいきます - テーブルが優先順位で処理されるので、列 "値"が "あいまい"であるすべての行が最初に処理されます。

私は定義可能な "重み"でレコードを注文するオプションを追加するという仕事を与えられました。たとえば、処理の50%を優先順位1、優先順位25%、優先順位25%としたいとします。したがって、上記から、100レコードごとに、50件が "価値" "、そのうち25人は"バランス "が50より大きいなどとなります。

私はこれを行う方法を理解しようとしています。「優先度」の重み付けされた値を増やすことが最善の方法と思われますが、これをコード化する方法について頭を悩ますことはできません。誰でも助けてくれますか?

編集:申し訳ありませんが、言ったはずです:これはMSSQL 2008で実行されている

5
どのバージョンのSQLを使用していますか?
追加された 著者 Curt,
Ooops、本当にそれを言及していたはずです。それはSQL 2008です
追加された 著者 KenD,
優先度の値を更新する必要があります。私たちのシステムはこのテーブルを優先的に読み込みます(事実上SELECT * FROMテーブルORDER BY優先順位)。
追加された 著者 KenD,
私たちは現在、逆の順序でステートメントを実行しています(これを反映するために質問を更新しました、残念です)。これは、「オーバーラップ」が最優先であることを意味します。私は重み付けでこれを実装する方法がわかりません - 簡単にするために、重み付けが常に1つのフィールドで行われると仮定するほうが簡単でしょう。値?
追加された 著者 KenD,
@リーブン:私はそれを考慮していなかった:(それは重み付け基準を満たすために "ベストエフォート"であるので、正確なパーセンテージの内訳を満たすために十分なレコードがない場合には、問題。
追加された 著者 KenD,
@StevieG:それは、オンザフライで生成された動的SQLの可能性が高いです。レコードは定期的には変更されませんが、このプロセスが実行されている間は確かに変更されません。
追加された 著者 KenD,
私は上手く理解できていない気がします。表に記載されている順番に更新する必要がありますか?更新する必要がありますか?
追加された 著者 Lieven Keersmaekers,
優先順位2(残高> 50)が1に変更される可能性があるとどのように判断していますか?
追加された 著者 Lieven Keersmaekers,
私はまだ端の場合を理解するのに困っている。テーブルに4つの優先順位3のレコードしかない場合はどうなりますか?どちらを2にし、どちらを1にするか?
追加された 著者 Lieven Keersmaekers,
は定期的に(つまり処理実行中に)変化するレコードの数ですか?何が処理をしていますか?ストアドプロシージャー、またはいくつかの外部プロセスですか?
追加された 著者 StevieG,

2 答え

一般的な考え方は、バケットにタスクを集め、整数の境界で分割することです:

select
  task_id
from (  
  select 
    task_id, 
    ((task_priority_order - 1)/task_priority_density) as task_processing_order
  from (
    select
      t.task_id                                            as task_id, 
      t.priority                                           as task_priority, 
      row_number() 
        over (partition by t.priority order by t.priority) as task_priority_order,
      case
        when t.priority = 3 then 50
        when t.priority = 2 then 25
        when t.priority = 1 then 25
      end                                                  as task_priority_density
    from
      table t
  )
)
order by task_processing_order

最初の50レコード(優先度3)、最初の25レコード(優先度2)、最初の25レコード(優先度1)から100レコードを得ました。

1.0から1.への次のディアパンソン(9)は、レコードの次のバケットを表します。

ある優先度の値を持つタスクがなくなると、残りのタスクは同じ割合でバケットに配置されます。例えば。優先度3のタスクが十分でない場合、残りのタスクは50/50の比率で整理されます。

task_id - タスク識別のためのいくつかの代理キー。

P.S.申し訳ありませんが、今はこのクエリをテストすることはできませんので、構文の修正は非常に感謝しています。

Update: Query syntax corrected according to comments.

5
追加された
CASE 文で priority_density task_priority_density に変更し、row_numberを row_number()に変更しました(パーティションはt.priority ORDER BY t.priority)-1としてtask_priority_order - それが正しいかどうかはわかりませんが、そうでない場合は不平を言いました。今はテストテーブルで美しく動作するようです。プロダクションシステムで作業するには、それを変更する必要がありますが、そこには90%の方法があります。 非常に非常に多くありがとう!
追加された 著者 KenD,
@ケニーアンダーソン:あなたのコメントのおかげで、答えは訂正。
追加された 著者 ThinkJet,

与えられたテストスクリプトは次の出力を提供します。最終結果が何であるべきかに関するいくつかのルールを定めるなら、私はそれをもう一度見てみたいと思います。

結果

Priority    Processed       Balance Value
3           NULL            NULL    NULL
NULL        0               49      NULL
NULL        1               49      NULL
NULL        0               50      NULL
NULL        1               50      NULL
2           0               51      NULL
2           1               51      NULL
2           0               51      Notblah
1           1               51      blah

テストスクリプト

DECLARE @Table TABLE (Priority INTEGER, Processed BIT, Balance INTEGER, Value VARCHAR(32))

INSERT INTO @Table VALUES 
  (NULL, NULL, NULL, NULL)
  , (NULL, 0, 49, NULL)
  , (NULL, 1, 49, NULL)
  , (NULL, 0, 50, NULL)
  , (NULL, 1, 50, NULL)
  , (NULL, 0, 51, NULL)
  , (NULL, 1, 51, NULL)
  , (NULL, 0, 51, 'Notblah')
  , (NULL, 1, 51, 'blah')

UPDATE @table SET priority=3 WHERE processed IS NULL
UPDATE @table SET priority=2 WHERE balance > 50
UPDATE @table SET priority=1 WHERE value = 'blah'

SELECT  *
FROM    @table
0
追加された