質問

この質問に加えて、複数の列に一致する明確な結果を提供するSQLクエリ 非常にきちんとした解決策を持っていた、私は次のステップがどのように見えるか疑問に思っていました:

 DOCUMENT_ID |     TAG
----------------------------
   1        |   tag1
   1        |   tag2
   1        |   tag3
   2        |   tag2
   3        |   tag1
   3        |   tag2
   4        |   tag1
   5        |   tag3

したがって、タグ1および2を持つすべてのdocument_idを取得するには、次のようなクエリを実行します。

SELECT document_id
FROM table
WHERE tag = 'tag1' OR tag = 'tag2'
GROUP BY document_id
HAVING COUNT(DISTINCT tag) = 2

さて、興味深いのは、タグ1と2を持つすべての個別のdocument_idと、それに加えてタグ3を持つidを取得する方法です。 同じクエリを作成し、それらの結合を実行することを想像できます。

SELECT document_id
FROM table
WHERE tag = "tag1" OR tag = "tag2"
GROUP BY document_id
HAVING COUNT(DISTINCT tag) = 2
UNION
SELECT document_id
FROM table
WHERE tag = "tag3"
GROUP BY document_id

しかし、その条件が追加されたら、別の初期クエリを考えることができるかどうか疑問に思いました。私は多くの「組合」を持つことを想像しています。異なるタグとタグカウントのようなものです。 そのような結合のチェーンを作成することは、パフォーマンスの点で非常に悪いことではありませんか?

役に立ちましたか?

解決

これは、まだ種類の結合を使用しますが、読みやすく、制御しやすいかもしれません。大規模なデータセットでのこのクエリの速度に非常に興味があるので、その速度を教えてください。小さなデータセットを入力すると、0.0001秒かかりました。

SELECT DISTINCT (dt1.document_id)
FROM 
  document_tag dt1,
  (SELECT document_id
    FROM document_tag
    WHERE tag =  'tag1'
  ) AS t1s,
  (SELECT document_id
    FROM document_tag
    WHERE tag =  'tag2'
  ) AS t2s,
  (SELECT document_id
    FROM document_tag
    WHERE tag =  'tag3'
  ) AS t3s
WHERE
  (dt1.document_id = t1s.document_id
  AND dt1.document_id = t2s.document_id
  )
  OR dt1.document_id = t3s.document_id

これにより、各タグの結果セットがすでに指定されているため、新しいパラメーターを簡単に追加できます。

追加例:

OR dt1.document_id = t2s.document_id

最後まで、document_id 2も取得します

他のヒント

これを単一で実行することは可能ですが、選言を使用するにはWHERE句をhaving句に昇格させる必要があります。

正しいです。追加のUNION句で検索する新しいタグを追加すると、ますます遅くなります。各UNION句は、計画して実行する必要がある追加のクエリです。さらに、完了したらソートすることはできません。

あなたは、基本的なデータウェアハウジング手法を探しています。最初に、1つの追加テーブルを使用してスキーマを再作成します。

create table a (document_id int, tag varchar(10));

insert into a values (1, 'tag1'), (1, 'tag2'), (1, 'tag3'), (2, 'tag2'), 
                     (3, 'tag1'), (3, 'tag2'), (4, 'tag1'), (5, 'tag3');

create table b (tag_group_id int, tag varchar(10));

insert into b values (1, 'tag1'), (1, 'tag2'), (2, 'tag3');

表bには「タググループ」が含まれています。グループ1にはtag1とtag2が含まれ、グループ2にはtag3が含まれます。

テーブルbを変更して、関心のあるクエリを表すことができます。クエリの準備ができたら、一時テーブルを作成して集計データを保存します。

create temporary table c 
(tag_group_id int, count_tags_in_group int, tags_in_group varchar(255));

insert into c
select 
    tag_group_id,
    count(tag),
    group_concat(tag)
from b
group by tag_group_id;

create temporary table d (document_id int, tag_group_id int, document_tag_count int);

insert into d
select
    a.document_id,
    b.tag_group_id,
    count(a.tag) as document_tag_count
from a
inner join b on a.tag = b.tag
group by a.document_id, b.tag_group_id;

現在、cにはタググループのタグの数が含まれ、dには各ドキュメントが各タググループに対して持つタグの数が含まれています。 cの行がdの行と一致する場合、その文書はそのタググループのすべてのタグを持っていることを意味します。

select 
    d.document_id as "Document ID",
    c.tags_in_group as "Matched Tag Group"
from d
inner join c on d.tag_group_id = c.tag_group_id
            and d.document_tag_count = c.count_tags_in_group

このアプローチの優れた点の1つは、「これらの各タググループに50%以上のタグを持つドキュメントの数」などのレポートを実行できることです

select 
    d.document_id as "Document ID",
    c.tags_in_group as "Matched Tag Group"
from d
inner join c on d.tag_group_id = c.tag_group_id
            and d.document_tag_count >= 0.5 * c.count_tags_in_group
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top