Pergunta

I última análise, precisamos de uma lista de registros de "importação" que incluem "álbum" registros que apenas têm uma "canção" cada um.

Isto é o que eu estou usando agora:

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

O SELECT aninhada (com a junção) é super rápido, mas o externo "In" cláusula é dolorosamente lento.

Eu tentei fazer a consulta inteira uma única (sem nidificação) participar, mas ran problemas com as cláusulas do grupo / ter. O melhor que eu podia fazer era uma lista de registros de "importação" com ingênuos, que não é aceitável.

Existe uma maneira mais elegante para compor esta consulta?

Foi útil?

Solução

Como é isso?

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; 

Na maioria dos sistemas de banco de dados, o JOIN funciona um perdido mais rápido do que fazendo um WHERE ... IN.

Outras dicas

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

(Você pode não precisar de incluir o COUNT na lista SELECT si. SQL Server não exigir isso, mas é possível que um RDBMS poder diferente.)

Não testado:

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)

Todas as três técnicas sugerido deve ser mais rápido do que o seu ONDE:

  1. existe com uma subconsulta relacionada (GBN)
  2. Subquery que é interior unidas (achinda99)
  3. Inner Juntando todas as três tabelas (luke)

(Todos devem trabalhar, também ..., então +1 para todos eles. Por favor, deixe-nos saber se um deles não funciona!)

Qual deles se transforma realmente a ser o mais rápido, depende de seus dados e o plano de execução. Mas um exemplo interessante de maneiras diferentes para expressar a mesma coisa em SQL.

Eu tentei fazer toda a consulta de um única (sem nidificação) participar, mas correu para problemas com o grupo / possuindo cláusulas.

Você pode juntar-se subconsulta usando CTE (Common Table Expression) se você estiver usando SQL Server versão 2005/2008

Tanto quanto eu sei, CTE é simplesmente uma expressão que funciona como uma visão virtual que funciona apenas um um único selecione declaração - Então, você será capaz de fazer o seguinte. Eu costumo encontrar usando CTE para melhorar a consulta de desempenho também.

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top