2017-11-07 7 views
3

データを集計値でソートし、次に他のフィールドでソートし、次に集計値でソートしたいとします。最小値でソートするために値をグルーピングし、次にその値で他のフィールドをソートする

私は、次のスキーマ持っている:私はどのように知っている

min_priority | priority | value | value_id | file_id 
    (hidden) |   |  | (hidden) |   
--------------+----------+-------+----------+--------- 
      10 |  10 | 654 |  4 |  444 
      10 |  20 | 654 |  4 |  444 
      10 |  10 | 876 |  2 |  333 
      10 |  10 | 987 |  1 |  111 
      10 |  20 | 987 |  1 |  111 
      20 |  20 | 765 |  3 |  111 
      20 |  20 | 876 |  2 |  222 

INSERT INTO priority_t (id, priority) VALUES (1, 10); 
INSERT INTO priority_t (id, priority) VALUES (2, 20); 

INSERT INTO value_t (id, value)  VALUES (1, 987); 
INSERT INTO value_t (id, value)  VALUES (2, 876); 
INSERT INTO value_t (id, value)  VALUES (3, 765); 
INSERT INTO value_t (id, value)  VALUES (4, 654); 

INSERT INTO file_t (id)    VALUES (111); 
INSERT INTO file_t (id)    VALUES (222); 
INSERT INTO file_t (id)    VALUES (333); 
INSERT INTO file_t (id)    VALUES (444); 

INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (1, 1, 1, 111); 
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (2, 2, 1, 111); 
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (3, 2, 2, 222); 
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (4, 1, 2, 333); 
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (5, 2, 3, 111); 
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (6, 1, 4, 444); 
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (7, 2, 4, 444); 

COMMIT; 

そして、私は次のような結果を取得したい:その後、私は、次のデータを挿入

CREATE TABLE priority_t (
    id   NUMERIC(10), 
    priority NUMERIC(10), 
    CONSTRAINT priority_t_pk PRIMARY KEY (id) 
); 

CREATE TABLE value_t (
    id   NUMERIC(10), 
    value  NUMERIC(10), 
    CONSTRAINT value_t_pk PRIMARY KEY (id) 
); 

CREATE TABLE file_t (
    id   NUMERIC(10), 
    CONSTRAINT file_t_pk PRIMARY KEY (id) 
); 

CREATE TABLE main_t (
    id   NUMERIC(10), 
    priority_id NUMERIC(10), 
    value_id NUMERIC(10), 
    file_id  NUMERIC(10), 
    CONSTRAINT main_t_pk PRIMARY KEY (id), 
    CONSTRAINT priority_t_fk FOREIGN KEY (priority_id) REFERENCES priority_t(id), 
    CONSTRAINT value_t_fk FOREIGN KEY (value_id) REFERENCES value_t(id), 
    CONSTRAINT file_t_fk FOREIGN KEY (file_id) REFERENCES file_t(id) 
); 

をそれらを並べ替える:

ORDER BY min_value ASC, value ASC, value_id ASC, priority ASC 

しかし、私の問題は、値自体をグループ化する方法がわからないことです。私は自分の行や重複した値に重複しています。

私の最も近いの試みは、次のとおりです。

WITH listing AS (
    SELECT m.id    AS main_id, 
     p.id    AS priority_id, 
     p.priority  AS priority, 
     v.id    AS value_id, 
     v.value   AS value, 
     f.id    AS file_id 
    FROM main_t m 
      INNER JOIN priority_t p ON m.priority_id = p.id 
      INNER JOIN value_t v ON m.value_id = v.id 
      INNER JOIN file_t f  ON m.file_id = f.id 
) 
SELECT min_p.min_priority AS min_priority, 
     listing.priority AS priority, 
     listing.value  AS value, 
     listing.file_id AS file_id 
    FROM listing, 
     (
     SELECT min(min_p_value.min_priority) AS min_priority, 
       min_p_value.value_id   AS min_value_id, 
       listing.file_id    AS file_id 
      FROM listing, 
       (
        SELECT min(listing.priority) AS min_priority, 
         listing.value   AS value, 
         listing.value_id  AS value_id 
        FROM listing 
        GROUP BY listing.value, listing.value_id 
       ) min_p_value 
      WHERE listing.value = min_p_value.value 
      AND listing.value_id = min_p_value.value_id 
      AND min_p_value.min_priority = min_priority 
      GROUP BY min_p_value.value_id, listing.file_id 
     ) min_p 
WHERE min_p.min_value_id = listing.value_id 
    AND min_p.file_id = listing.file_id 
ORDER BY min_p.min_priority ASC, 
      listing.value ASC, 
      listing.value_id ASC, 
      listing.priority; 

そして、これは、次の誤った結果を返します:

MIN_PRIORITY PRIORITY  VALUE FILE_ID 
------------- ---------- ---------- ---------- 
      10   10  654  444 
      10   20  654  444 
      10   10  876  333 
      10   20  876  222 <-- incorrect, should have a min_priority of 20, and therefore be the last 
      10   10  987  111 
      10   20  987  111 
      20   20  765  111 

どのように私は私が期待するものを達成することができますか?

+0

あなたの望ましい結果が与えられたテストデータに適合していないようだ私はこのようなものになるだろう、と思います。 value_id = 3は結果で2回発生しますが、テストデータでは1回だけ発生しますか? –

+0

@FrankOckenfussありがとう、ありがとうございます。私は 'value_id = 3、value = 765'の代わりに' value_id = 2、value = 876'を期待していました。私はその問題を解決した。 –

+0

min(優先度)をvalue_idでグループ化しますか? –

答えて

1

これは動作するはずです:

select (select min(priority) 
      from main_t mm 
      join priority_t tt 
      on tt.id = mm.priority_id 
     where mm.value_id = m.value_id) as min_priority, 
     p.priority as priority, 
     v.value as value, 
     m.value_id, 
     m.file_id 
    from main_t m 
    join priority_t p 
    on p.id = m.priority_id 
    join value_t v 
    on v.id = m.value_id 
order by 1, 3, 4, 2; 

それはVALUE_IDで最小の優先順位を決定します。 結果を図のように列番号順に並べ替えることができます。

+0

これは正しいようです。私はあなたの答えを受け入れるつもりです。しかし、私は私の質問で特定のケースを忘れてしまったので、(min_priority、value、file_idに基づいて、file_idが存在する全理由で)重複を見るべきではないはずです。これは適応するのが簡単ですか?そうでなければ、別の質問を作成します。 –

+0

* priority *、value、file_idに基づいて重複を削除したいと思いますか? –

+0

いいえ、 'min_priority'です。とにかく、パイプライン化された関数、すなわちOracleの特異性を持つ方法を発見しました。とにかくありがとう! :-) –

0

私はこのコードをMySQL(Oracle以外)に書いてあり、CTEの構文についてはわからないので、WITH句をmin_priorityという一時テーブルに置き換えましたが、もちろんtempテーブルをCTEで置き換えることもできます。これをMySQlで実行したとき、私はあなたが望むのと同じ結果を得ました。

また、左結合または内部結合が必要かどうかは不明でしたが、この例ではどちらも機能します。

-- find min priority for each value 
create temporary table if not exists min_priority as (
select m.value_id, min(p.priority) as min_pri 
from main_t m 
inner join priority_t p on m.priority_id = p.id 
group by m.value_id 
); 

-- just join all the tables, including min_priority, and order the result 
select mp.min_pri, p.priority, v.value, v.id, f.id 
from main_t m 
left join priority_t p on m.priority_id = p.id 
left join value_t v on m.value_id = v.id 
left join file_t f on m.file_id = f.id 
left join min_priority mp on mp.value_id = v.id 
order by mp.min_pri asc, v.value asc, v.id asc, p.priority asc; 

パフォーマンスに影響するため、質問の例として複数のレベルの内部クエリを使用しません。

0

集計値と非集計値が必要な場合は、analytic functionsを使用してください。

select * 
    from (select min(p.priority) over (partition by v.id, v.value, f.id) min_priority, 
       p.priority, v.value, v.id value_id, f.id file_id 
      from main_t m 
      join priority_t p on m.priority_id = p.id 
      join value_t v on m.value_id = v.id 
      join file_t f  on m.file_id = f.id) 
    order by min_priority, value, value_id, priority 

結果:

MIN_PRIORITY PRIORITY  VALUE VALUE_ID  FILE_ID 
------------ ----------- ----------- ----------- ----------- 
      10   10   654   4   444 
      10   20   654   4   444 
      10   10   876   2   333 
      10   10   987   1   111 
      10   20   987   1   111 
      20   20   765   3   111 
      20   20   876   2   222 
関連する問題