6

SQL Server 2008を使用するテーブルがあり、2つの並べ替え可能な列があるテーブルがあり、1つは手動で設定され、もう1つはシステムプロシージャによって計算されます(このプロシージャはすべてを全体として並べ替え、10から一番上の行まで並べ替えを割り当てます回数10)

ID    Manual     System
------------------------
1      null      300
2      2         380
3      null      500
4      null      200

そして私はそれを取得してIDを4、2、1、3にソートしようとしています

それが適用されたときに、出力がシステム上で手動ソートを取得するようにしたいと思います。別の行が追加され、手動で並べ替える場合も考慮する必要がある場合は、さらに複雑になります。

ID    Manual     System
-----------------------
1      null      300
2      2         380
3      null      500
4      null      200
5      5         100

したがって、新しい並べ替えは4,2,1,3,5になります

ID    Manual     System
-----------------------
4      null      200
2      2         380
1      null      300
3      null      200
5      5         100

何か案は?そして、Rank、Dense_Rank、Row_Numberなどを試しました。

与えられた解決策は私の例では正しいようです。ここでも要因となる3番目の列personIDがあることを忘れました。

ID    Manual     System    PersonID
-------------------------------------
4      null      200         22
2      2         380         22
1      null      300         22
3      null      200         22
5      5         100         22
8      1         210         25
6      1         480         25
7      null      600         25
9      4         800         25
10     null      990         25

だから私は最初にそれらを人で注文し、次に手動で注文し、次に並べ替える必要があります。それでも問題が発生するようです。

4

3 に答える 3

3

これがあなたに必要なものだと思います。説明するのは少し難しいです。

Basically inserting not null manual values as row index (or row number) to the record list ordered by system.

フィドルデモ

;with cte as (
    select id, manual,system,
           convert(decimal(10,1),row_number() over(order by system)) rn
    from t
    where manual is null 
    union all
    select id, manual,system, convert(decimal(10,1),manual-0.5) rn
    from t
    where manual is not null
)
select id,manual,system
from cte
order by rn


| ID | MANUAL | SYSTEM |
------------------------
|  4 | (null) |    200 |
|  2 |      2 |    380 |
|  1 | (null) |    300 |
|  3 | (null) |    500 |
|  5 |      5 |    100 |
于 2013-02-25T15:57:54.443 に答える
3

要件を理解している場合は、[手動]列が提供されていない限り、[システム]列で並べ替えます。その場合は、代わりにそれを並べ替え位置として使用しますか?もしそうなら、これはあなたがとを使用して動作するはずCASEですROW_NUMBER

SELECT Id, Manual, System
FROM (
  SELECT Id, 
    Manual, 
    System,
    ROW_NUMBER() OVER (ORDER BY Manual, System)  rn
  FROM YourTable) t
ORDER BY CASE WHEN Manual IS NULL THEN RN ELSE Manual END, COALESCE(Manual,RN+1)

SQLフィドルデモ

于 2013-02-25T16:32:16.533 に答える
3

これが私の解決策です:http ://sqlfiddle.com/#!3 / a32a0 / 1/0

SELECT *
FROM
(
  SELECT
    ID
    , ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY System)-.1 AS rn
    , Manual
    , System
    , PersonID
  FROM YourTable
) t0
ORDER BY PersonID
  , COALESCE(Manual, RN)

説明は次のとおりです。

  • 行番号を基本行番号として使用しています。しかし、PersonIDの上位インデックスで最初に注文するので、これをPARTITION BY...行う前にORDER BY...、の各グループのインデックスをリセットします。MANUAL
  • ROW_NUMBERの自然な順序と並べ替えが同点の場合、MANUAL.1((0,1)の間の任意の量)を減算します。MANUALこれにより、同点の場合の値が優先されます
  • 最終結果の順序付けに関しては、最初ORDER BYPARTITION BY値を指定し、適切なグループ化を最初に確認してから、およびの最初の非null値でMANUAL順序付けます。RN

試してみる。+前の2つの回答の開始点を指します。そのうちの1つを出発点として使用し、そこから書き直しました。

編集:.1の減算を削除し、オプティマイザーをランクよりも手動を優先するように「トリック」する新しいランク付け関数を追加しました。これがすべての場合に当てはまるのか、それともオプティマイザーが他の状況でこの順序で結果を出せないのかはわかりませんが、役立つ場合に備えて、調査結果を含めたいと思いました。

更新されたクエリは次のとおりです。

SELECT *
  FROM
  (
    SELECT
      ID
      , ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY System) AS rn
      , ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Manual) AS rn_throwaway
      , Manual
      , System
      , PersonID
    FROM YourTable
  ) t0
ORDER BY PersonID
  , COALESCE(Manual, RN)

また、使用例はhttp://sqlfiddle.com/#!3/1831d/55/0およびhttp://sqlfiddle.com/#!3/a32a0/9/0にあります。

于 2013-02-26T15:25:12.167 に答える