web-dev-qa-db-ja.com

GROUP BYおよびORDER BYの問題

次のような2つのテーブルがあります。

_CREATE TABLE cmap5 (
   name     varchar(2000),
   lexemes  tsquery
);
_

そして

_CREATE TABLE IF NOT EXISTS synonyms_all_gin_tsvcolumn (
   cid       int NOT NULL,  -- REFERENCES pubchem_compounds_index(cid)
   name      varchar(2000) NOT NULL,  
   synonym   varchar(2000) NOT NULL,
   tsv_syns  tsvector,
   PRIMARY KEY (cid, name, synonym)
);
_

私の現在のクエリは:

_SELECT s.cid, s.synonym, c.name, ts_rank(s.tsv_syns,c.lexemes,16) 
FROM synonyms_all_gin_tsvcolumn s, cmap5 c
WHERE c.lexemes @@ s.tsv_syns
_

そして出力は:

_cid     |  synonym                              | name (query)              | rank
5474706 | 10-Methoxyharmalan                    | 10-methoxyharmalan        | 0.0901673
1416    | (+/-)12,13-EODE                       | 12,13-EODE                | 0.211562
5356421 | LEUKOTOXIN B (12,13-EODE)             | 12,13-EODE                | 0.211562
 180933 | 1,4-Chrysenequinone                   | 1,4-chrysenequinone       | 0.211562
5283035 | 15-Deoxy-delta-12,14-prostaglandin J2 | 15-delta prostaglandin J2 | 0.304975
5311211 | 15-deoxy-delta 12 14-prostaglandin J2 | 15-delta prostaglandin J2 | 0.304975
5311211 | 15-deoxy-Delta(12,14)-prostaglandin J2| 15-delta prostaglandin J2 | 0.304975
5311211 | 15-Deoxy-delta-12,14-prostaglandin J2 | 15-delta prostaglandin J2 | 0.304975
5311211 | 15-Deoxy-delta 12, 14-Prostaglandin J2| 15-delta prostaglandin J2 | 0.304975
_

ts_rank()関数によってランク付けされたメインテーブルの_cmap5_のすべての行の名前の一致を返したいのですが、_cmap5_の各行について、次のことを実行します。

  • 各クエリに最適なX cidsのみを選択(_group by cid_)
  • またはORDER BY my results as 1+ts_rank/count(cid)

最適な一致を得るために_select distinct on c.name_を追加しようとしましたが、ランクが同じである場合は、クエリにさらに一致するcidを取得します。クエリの最後に簡単なグループを追加しようとしましたが、エラーが発生しました。どうすればよいですか?

追加されたコメント:

一方では、ランクが同じである結果、たとえば上記の_5283035_および_5311211_の場合、cidは_5311211_よりもヒット数が多いため、上位の結果として_5283035_を取得します。ヒット数/ランク内のcid、final_rank = 1 + ts_rank(cid)/ noなど。ヒット数(cid)。

一方、クエリ名ごとに最初のX cidsを取得したいと思います。 _LIMIT X_を使用すると、クエリテーブルの最初のXではなく最初のX結果が返されます名前ごと(行)私が望むように。

6
mcasfrox

まず、2つのvarchar(2000)列にまたがる_PRIMARY KEY_は非常に高価に見えます。他の目的でPKを使用する場合は、代理PK( serial column を使用)を提案し、UNIQUE制約を追加して_(cid, name, synonym)_に一意性を適用します。

varchar列の1つが実際に最大長を使用する場合、インデックスエントリの最大サイズを超えます。見る:

私は推測あなたが望むのはこれです、それは理にかなっているので:

_SELECT DISTINCT ON (c.name)
       c.name, min(s.synonym) AS min_synonym, s.cid
     , ts_rank(s.tsv_syns, c.lexemes, 16) AS rnk
     , count(*) AS ct
FROM   synonyms_all_gin_tsvcolumn s
JOIN   cmap5                      c ON c.lexemes @@ s.tsv_syns
GROUP  BY c.name, rnk, s.cid
ORDER  BY c.name, rnk DESC, ct DESC;
_
  • 明示的な_[INNER] JOIN_を使用し、_CROSS JOIN_プラスWHERE句の代わりに、結合条件を付加します。これは一般的に優れている(読み取りとデバッグが容易)と考えられています。また、列名としてrnkを使用して、基本的な関数名rankを識別子として回避しています。

  • rnkと_c.name_が同じ_s.cid_ごとに結果をグループ化し、min(s.synonym)(質問の定義がない場合)、およびcount(*)グループごとのピア。

  • _c.name_(SQL標準DISTINCTのPostgres固有の拡張)を使用して_DISTINCT ON_ごとに1行に減らし、最も高いランクを最初に、同じランク内で最も高いピアカウントを取得します。見る:

  • 各GROUP BYグループの最初の行を選択しますか?

_GROUP BY_と_DISTINCT ON_をこのように1つのクエリレベルで組み合わせることは、DISTINCTまたは_DISTINCT ON_がafter_GROUP BY_。

9