Question

J'ai besoin en fin de compte une liste de « importer » des documents qui incluent « album » dossiers qui ont seulement une « chanson » chacun.

est ce que je suis maintenant avec:

select i.id, i.created_at 
from imports i 
where i.id in (
    select a.import_id 
    from albums a inner join songs s on a.id = s.album_id
    group by a.id having 1 = count(s.id)
);

La sélection (avec la jointure) imbriquée est ultra-rapide, mais l'extérieur "Dans" clause est atrocement lent.

J'ai essayé de faire toute la requête d'un seul (pas d'imbrication), mais couru rejoindre des problèmes avec les clauses de groupe / ayant. Le mieux que je pouvais faire était une liste des dossiers « d'importation » avec dupes ce qui est inacceptable.

Y at-il une façon plus élégante pour composer cette requête?

Était-ce utile?

La solution

Comment ce?

SELECT i.id,
       i.created_at
FROM   imports i
       INNER JOIN (SELECT   a.import_id
                   FROM     albums a
                            INNER JOIN songs s
                              ON a.id = s.album_id
                   GROUP BY a.id
                   HAVING   Count(* ) = 1) AS TEMP
         ON i.id = TEMP.import_id; 

Dans la plupart des systèmes de base de données, les œuvres REJOIGNEZ une perte plus rapide que de faire WHERE ... IN.

Autres conseils

SELECT i.id, i.created_at, COUNT(s.album_id)
FROM imports AS i
    INNER JOIN albums AS a
        ON i.id = a.import_id
    INNER JOIN songs AS s
        ON a.id = s.album_id
GROUP BY i.id, i.created_at
HAVING COUNT(s.album_id) = 1

(Vous ne pourriez pas besoin d'inclure le COUNT dans la liste SELECT lui-même. SQL Server ne nécessite pas, mais il est possible qu'une puissance SGBDR différente.)

Untested:

select
    i.id, i.created_at
from
    imports i
where
    exists (select *
       from
           albums a
           join
           songs s on a.id = s.album_id
       where
           a.import_id = i.id
       group by
           a.id
       having
           count(*) = 1)

ou

select
    i.id, i.created_at
from
    imports i
where
    exists (select *
       from
           albums a
           join
           songs s on a.id = s.album_id
       group by
           a.import_id, a.id
       having
           count(*) = 1 AND a.import_id = i.id)

Les trois techniques sugested devraient être plus rapide que WHERE IN:

  1. coexiste avec une sous-requête associée (GBN)
  2. sous-requête qui est interne joint (achinda99)
  3. intérieur joindre les trois tableaux (luke)

(Tout le monde devrait travailler aussi ..., donc +1 pour tous. S'il vous plaît laissez-nous savoir si l'un d'eux ne fonctionne pas!)

Lequel se fait avéré être le plus rapide, dépend de vos données et le plan d'exécution. Mais un exemple intéressant de façons différentes pour exprimer la même chose dans SQL.

  

J'ai essayé de faire l'une de toute requête   unique (pas de nidification) se joindre, mais a couru dans   problèmes avec le groupe / ayant   clauses.

Vous pouvez vous joindre à l'aide de CTE sous_requête (Common Table Expression) si vous utilisez la version SQL Server 2005/2008

Pour autant que je sache, CTE est tout simplement une expression qui fonctionne comme une vue virtuelle qui fonctionne seul un instruction select - Vous serez en mesure de faire ce qui suit. Je trouve généralement en utilisant CTE pour améliorer les performances des requêtes ainsi.

with AlbumSongs as (
    select  a.import_id 
    from    albums a inner join songs s on a.id = s.album_id
    group by a.id 
    having 1 = count(s.id)
)
select  i.id, i.created_at 
from    imports i 
        inner join AlbumSongs A on A.import_id = i.import_id
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top