web-dev-qa-db-fra.com

GROUPE PAR et ORDRE PAR problème

J'ai deux tableaux comme celui-ci:

CREATE TABLE cmap5 (
   name     varchar(2000),
   lexemes  tsquery
);

et

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)
);

Ma requête actuelle est:

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

Et la sortie est:

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

Je voudrais renvoyer les correspondances de noms de toutes les lignes de cmap5 Dans ma table principale classées par la fonction ts_rank() mais pour chaque ligne de cmap5 Je veux:

  • sélectionner uniquement les meilleurs X cids pour chaque requête (group by cid)
  • ou ORDER BY my results as 1+ts_rank/count(cid)

Pour obtenir la meilleure correspondance, j'ai essayé d'ajouter select distinct on c.name, Mais lorsque le rang est le même, je veux obtenir le cid avec plus de correspondances à la requête. J'ai essayé d'ajouter un groupe simple à la fin de la requête mais j'obtiens une erreur, comment faire?

Commentaires ajoutés:

D'une part pour les résultats dont le rang est le même, par exemple. au-dessus de 5283035 et 5311211, obtenez 5311211 comme résultat supérieur parce que cid a plus de hits que 5283035, donc je veux en quelque sorte prendre en compte le nombre de hits/cid dans le classement, comme final_rank = 1 + ts_rank (cid)/no. de coups (cid).

D'un autre côté, je veux obtenir les premiers X cids par nom de requête. Si j'utilise LIMIT X, Il renvoie les premiers X résultats de la table de requête entière, pas le premier Xpar nom (ligne) de la requête table comme je veux.

6
mcasfrox

Tout d'abord, votre PRIMARY KEY Sur deux colonnes varchar(2000) semble extrêmement cher. Si vous utilisez votre PK pour autre chose, je suggère un PK de substitution (utilisez une colonne serial ) et ajoutez une contrainte UNIQUE pour appliquer l'unicité sur (cid, name, synonym).

Si l'une de vos colonnes varchar utilise réellement la longueur maximale, vous dépasseriez la taille maximale pour une entrée d'index. Voir:

Je suppose ce que vous voulez, c'est parce que cela aurait du sens:

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;
  • J'utilise [INNER] JOIN Explicite avec une condition de jointure jointe remplaçant votre CROSS JOIN Plus WHERE clause. Il est généralement considéré comme supérieur (plus facile à lire et à déboguer). J'utilise également rnk comme nom de colonne pour éviter le nom de fonction de base rank comme identifiant.

  • Regroupez les résultats par c.name Qui ont les mêmes rnk et s.cid, Prenez min(s.synonym) (faute de définition dans la question) et count(*) les pairs par groupe.

  • Réduisez à une ligne par c.name Avec DISTINCT ON (Extension spécifique Postgres du standard SQL DISTINCT), en prenant le rang le plus élevé en premier et, dans le même rang, le nombre d'homologues le plus élevé. Voir:

  • Sélectionnez la première ligne de chaque groupe GROUP BY?

La combinaison de GROUP BY Et DISTINCT ON De cette façon dans un niveau de requête est possible car DISTINCT ou DISTINCT ON Sont appliqués après GROUP BY.

9