1

おおよそ次のような表があります。

CREATE TABLE t_table (
    f_userid       BIGINT NOT NULL
   ,f_groupaid     BIGINT
   ,f_groupbid     BIGINT
   ,f_groupcid     BIGINT
   ,f_itemid       BIGINT
   ,f_value        TEXT
);

グループは直交しているため、テーブル内のすべてのエントリにユーザー ID があるという事実を超えて階層を暗示することはできません。どの列にも一意性はありません。

たとえば、簡単なセットアップは次のようになります。

INSERT INTO t_table VALUES (1, NULL, NULL, NULL, NULL, 'Value for anything by user 1');
INSERT INTO t_table VALUES (1,    5,    2, NULL, NULL, 'Value for anything by user 1 in groupA 5 groupB 2');
INSERT INTO t_table VALUES (1,    4, NULL,    1, NULL, 'Value for anything by user 1  in groupA 5 and groupC 1');
INSERT INTO t_table VALUES (2, NULL, NULL, NULL, NULL, 'Value for anything by user 2');
INSERT INTO t_table VALUES (2,    1, NULL, NULL, NULL, 'Value for anything by user 2 in groupA 1');
INSERT INTO t_table VALUES (2,    1,    3,    4,    5, 'Value for item 5 by user 2 in groupA 1 and groupB 3 and groupC 4');

ユーザー/グループA/グループB/グループC/アイテムの特定のセットについて、適用されるテーブルで最も具体的なアイテムを取得できるようにしたいと考えています。指定されたセットのいずれかが NULL の場合、NULL を含むテーブル内の関連する列のみに一致できます。例えば:

// Exact match
SELECT MostSpecific(1, NULL, NULL, NULL, NULL) => "Value for anything by user 1" 
// Match the second entry because groupC and item were not specified in the table and the other items matched
SELECT MostSpecific(1, 5, 2, 3, NULL) => "Value for anything by user 1 in groupA 5 groupB 2"
// Does not match the second entry because groupA is NULL in the query and set in the table
SELECT MostSpecific(1, NULL, 2, 3, 4) => "Value for anything by user 1"

ここでの明らかなアプローチは、ストアド プロシージャがパラメーターを処理し、どれが NULL でどれがそうでないかを調べてから、適切な SELECT ステートメントを呼び出すことです。しかし、これは非常に効率が悪いようです。これを行うより良い方法はありますか?

4

3 に答える 3

0

次のようなものを試してください:

select *
from t_table t

where f_userid = $p_userid
  and (t.f_groupaid is not distinct from $p_groupaid or t.f_groupaid is null) --null in f_groupaid matches both null and not null values
  and (t.f_groupbid is not distinct from $p_groupbid or t.f_groupbid is null)
  and (t.f_groupcid is not distinct from $p_groupcid or t.f_groupcid is null)

order by (t.f_groupaid is not distinct from $p_groupaid)::int -- order by count of matches
        +(t.f_groupbid is not distinct from $p_groupbid)::int
        +(t.f_groupcid is not distinct from $p_groupcid)::int desc
limit 1;

グループでのベストマッチを提供します。

A is not distinct from BtrueA と B が等しいか、または両方である場合に返されnullます。

::intを意味しcast ( as int)ます。ブール値をキャストtrueするintと得られます1(ブール値を直接追加することはできません)。

于 2013-07-31T15:12:00.370 に答える