none
Select em 2 tabelas RRS feed

  • Pergunta

  • Pessoal

     

    Como poderia efetuar uma instrução select em 2 tabelas (tabCarros,tabAcessorios) relacionadas pela PK Codcarro no seguinte cenário:

     

    tabCarros

    Codcarro

    Carro

     

    tabAcessorios

    CodAcess

    Codcarro

    Acessório

     

    Meu problema é o seguinte:  Preciso achar o Carro certo com os acessórios que eu definir. Por exemplo: “Quero um carro com: radio,roda,limpador traseiro”. O retorno dessa query seria o carro que contém todos estes acessórios. Aqueles carros que não tiverem "radio,roda,limpador traseiro” no mínimo não deverão aparecer no resultado.

     

    Valeu

     

    segunda-feira, 12 de janeiro de 2009 13:17

Respostas

  •  

     

    -- Solução 1

    -- Utiliza a interseção entre os carros que tem roda, radio e limpador traseiro

    ;WITH CarrosEscolhidos AS (

    SELECT CodCarro FROM tabAcessorios WHERE Acessorio LIKE '%rodas%'

    INTERSECT

    SELECT CodCarro FROM tabAcessorios WHERE Acessorio LIKE '%radio%'

    INTERSECT

    SELECT CodCarro FROM tabAcessorios WHERE Acessorio LIKE '%limpador traseiro%')

     

    -- Combina os carros encontrados com seus acessórios

    SELECT C.CodCarro, C.Carro, A.Acessorio

    FROM tabCarros AS C

    INNER JOIN tabAcessorios AS A ON C.CodCarro = A.CodCarro

    WHERE C.CodCarro IN (SELECT CodCarro FROM CarrosEscolhidos)

     

     

    -- Solução 2

    ;WITH CarrosEscolhidos AS (

    SELECT CodCarro FROM tabAcessorios

    WHERE

    Acessorio LIKE '%rodas%' OR

    Acessorio LIKE '%radio%' OR

    Acessorio LIKE '%limpador traseiro%'

    GROUP BY CodCarro

    HAVING COUNT(DISTINCT Acessorio) >= 3)

     

    -- Combina os carros encontrados com seus acessórios

    SELECT C.CodCarro, C.Carro, A.Acessorio

    FROM tabCarros AS C

    INNER JOIN tabAcessorios AS A ON C.CodCarro = A.CodCarro

    WHERE C.CodCarro IN (SELECT CodCarro FROM CarrosEscolhidos)

     

     

    Como eu havia dito existem mais quatro formas de resolver isso. A terceira forma é baseada no pivoteamento e está presente no meu webcast (recomendo assistí-lo). A quarta forma é baseada em lógica reserva e estarei demonstrando-a em uma atualização no meu blog em breve.

     

    Se possível tente não utilizar o LIKE. Mostre uma lista prévia de acessórios e faça com que o usuário os escolha. O LIKE pode inviabilizar algumas das soluções propostas.

     

    [ ]s,

     

    Gustavo Maia Aguiar

    http://gustavomaiaaguiar.spaces.live.com

     

    segunda-feira, 12 de janeiro de 2009 21:51

Todas as Respostas

  • Carlos,

     

         Neste caso, basta um SQL Simples

     

    Neste primeiro SQL, só será retornado os carros com acessórios cadastrados.

     

    Code Snippet

    SELECT

         c.Codcarro

         c.Carro,

         a.CodAcess,

         a.Codcarro,

         a.Acessório

    FROM tabCarros c inner join tabAcessorios a on (c.CodCarro = a.CodCarro)

     

     

    Neste segundo SQL, serão retornados todos os carros (mesmo se não exibir nenhum acessório cadastrado).

     

    Code Snippet

    SELECT

         c.Codcarro

         c.Carro,

         a.CodAcess,

         a.Codcarro,

         a.Acessório

    FROM tabCarros c left join tabAcessorios a on (c.CodCarro = a.CodCarro)

     

     

     

     

    [ ]'s

     Laércio.


    Ajude a melhorar o nosso Fórum!
    Não esqueça de marca a mensagem como "útil", caso tenha ajudado.

     

     

     

    segunda-feira, 12 de janeiro de 2009 13:28
  • Carlos,

     

     

           Estou movendo o seu post para o fórum de SQL Server (tem uma turma muito boa).

     

     

     

    segunda-feira, 12 de janeiro de 2009 13:29
  • Carlos,

     

    Além de utilizar os comandos de Join para realizar este tipo de Select, é possível também utilizar no mesmo código a claúsula Where, como um parâmetro para filtro de dados, veja abaixo o exemplo:

     

    Code Snippet

    SELECT

         c.Codcarro

         c.Carro,

         a.CodAcess,

         a.Codcarro,

         a.Acessório

    FROM tabCarros c inner join tabAcessorios a

                    on (c.CodCarro = a.CodCarro)

    Where c.CodCarro = 1

     

     

     

    Mesmo que você tenha criado um relacionamento através de Join, o SQL Server permite trabalhar de forma dinâmica com os valores existentes em ambas as tabelas, aumentando a flexibilidade da busca de informações.

     

    Code Snippet

    SELECT

         c.Codcarro

         c.Carro,

         a.CodAcess,

         a.Codcarro,

         a.Acessório

    FROM tabCarros c inner join tabAcessorios a

                    on (c.CodCarro = a.CodCarro)

    Where c.CodCarro In (1,3,5)

     

     

     

     

    segunda-feira, 12 de janeiro de 2009 13:38
  • Ok Laercio

     

    Obrigado pela ajuda.

    segunda-feira, 12 de janeiro de 2009 13:39
  •  

    Junior

     

    Obrigado desde já a ajuda, só que meu problema ainda não foi resolvido. pois na cláusula where eu preciso usar o a.acessorio. E se eu buscar mais do que 1 acessório, está vindo registros que não cumprem o que eu espero.

    Por exemplo:

     

    SELECT

         c.Codcarro

         c.Carro,

         a.CodAcess,

         a.Codcarro,

         a.Acessório

    FROM tabCarros c inner join tabAcessorios a

                    on (c.CodCarro = a.CodCarro)

    Where (a.acessorio like 'radio') or (a.acessorio like 'roda') or (a.acessorio like 'limpador traseiro')

     

    Para mim, está claro que o operador OR está incluindo os registros que não cumprem o que eu quero, só que se eu usar AND aí não me retorna nada pois o mesmo registro não pode ser por exemplo roda,radio,limpador ao mesmo tempo.

    segunda-feira, 12 de janeiro de 2009 13:53
  • Calos,

     

       Veja se resolve:

     

    Code Snippet

    SELECT

         c.Codcarro

         ,c.Carro

         ,a.CodAcess

         ,a.Codcarro

         ,a.Acessório

    FROM tabCarros c inner join tabAcessorios a

                    on (c.CodCarro = a.CodCarro)

    Where (a.acessorio like '%radio%' or a.acessorio like '%roda%' or a.acessorio like '%limpador traseiro%')

    and c.Carro = 'Ford Ka'

     

     

     

    * Neste exemplo estou fazendo uma pesquisa para selecionar os acessórios que contenha as palavras em qualquer parte do texto de um carro especifico.

     

     

    Para vários carros:

     

    SELECT

         c.Codcarro

         ,c.Carro

         ,a.CodAcess

         ,a.Codcarro

         ,a.Acessório

    FROM tabCarros c inner join tabAcessorios a

                    on (c.CodCarro = a.CodCarro)

    Where (a.acessorio like '%radio%' or a.acessorio like '%roda%' or a.acessorio like '%limpador traseiro%')

    and c.Carro in ('Ford Ka', 'Celta')

     

    Espero ter ajudado.

    segunda-feira, 12 de janeiro de 2009 14:32
  • Laercio

     

    Infelizmente o problema ainda persiste pois:

     

    Por exemplo:

    Ford Ka pode ter várias combinações de acessórios como radio + roda ou roda + limpador ou somente limpador, etc. Eu gostaria de ter um carro com Radio + Roda somente e por causa do operador OR, ele vai selecionar todos os registros que tenha roda + todos os registros que tenha Radio sendo que alguns carros vão ter apenas roda, outros Radio e outros Radio + Roda

     

    Outra questão é sobre o carro... eu não posso colocar o carro na cláusula where pois eu não sei que carro eu quero, mas sei que gostaria de ter qualquer um com radio + roda por exemplo.

    segunda-feira, 12 de janeiro de 2009 15:26
  • Carlos,

     

    Mas porque você esta utilizando o like?

     

    Quantos produtivos você desejaria pesquisar?

    segunda-feira, 12 de janeiro de 2009 16:10
  • Junior

     

    Posso estar utilizando outro operador de comparação como o "=", mas não muda o resultado para mim ainda. Eu utilizo o like porque o usuário do sistema pode ter a comodidade de digitar somente "rad" em vez de "rádio". No exemplo esqueci de mencionar que utilizo "%" antes e depois. < like '%rad%'>

     

    segunda-feira, 12 de janeiro de 2009 16:15
  •  Carlos Wakamatsu wrote:
    Laercio

     

    Infelizmente o problema ainda persiste pois:

     

    Por exemplo:

    Ford Ka pode ter várias combinações de acessórios como radio + roda ou roda + limpador ou somente limpador, etc. Eu gostaria de ter um carro com Radio + Roda somente e por causa do operador OR, ele vai selecionar todos os registros que tenha roda + todos os registros que tenha Radio sendo que alguns carros vão ter apenas roda, outros Radio e outros Radio + Roda

     

    Outra questão é sobre o carro... eu não posso colocar o carro na cláusula where pois eu não sei que carro eu quero, mas sei que gostaria de ter qualquer um com radio + roda por exemplo.

     

    Entendi, agora vai.

     

    Code Snippet

    SELECT

         c.Codcarro

         ,c.Carro

         ,a.CodAcess

         ,a.Codcarro

         ,a.Acessório

    FROM tabCarros c inner join

     

    (SELECT CodCarro,

                 count(CASE WHEN a.CodAcess = 1 THEN 1 ELSE 0 END) AS TotalRodas,

                 count(CASE WHEN a.CodAcess = 2 THEN 1 ELSE 0 END) AS TotalRadios

    FROM tabAcessorios

    group by CodCarro ) tabAcessorios a

                    on (c.CodCarro = a.CodCarro)

    Where (a.acessorio = 1 and a.acessorio = 2)

    and c.Carro in ('Ford Ka', 'Celta')

     

     

    Observações:

     

    Criei uma sub-consulta para agrupar os acessórios por carro. Dessa forma é possível identificar em uma única linha se um determinado carro possui Rodas e Som por exemplo.

     

    Code Snippet

    SELECT CodCarro,

                 count(CASE WHEN a.CodAcess = 1 THEN 1 ELSE 0 END) AS TotalRodas,

                 count(CASE WHEN a.CodAcess = 2 THEN 1 ELSE 0 END) AS TotalRadios

    FROM tabAcessorios

    group by CodCarro 

     

     

     

    Nos exemplos utilizei o código 1 para identificar os acessórios do tipo Roda e 2 para identificar os Rádios.

     

    [ ]'s

     Laércio.


    Ajude a melhorar o nosso Fórum!
    Não esqueça de marca a mensagem como "útil", caso tenha ajudado.

     

     

    segunda-feira, 12 de janeiro de 2009 16:43
  • Boa Tarde Carlos,

     

    Embora sua pergunta pareça absurdamente simples, não é tão simples expressá-la em uma cláusula WHERE. Essa é a natureza de um problema conhecido como "Divisão Relacional" e tem algumas formas de expressá-la.

     

    Abordei esse problema em um dos meus Webcasts (Mais Dicas e Mais Truques sobre consultas complexas) disponível para download no site do MSDN. Já estou com o artigo quase pronto para colocar no blog.

     

    Mas deixando de lado, as explicações da natureza do problema e antes de entrar na solução, qual versão do SQL Server você está usando ?

     

    [ ]s,

     

    Gustavo Maia Aguiar

    http://gustavomaiaaguiar.spaces.live.com

     

    segunda-feira, 12 de janeiro de 2009 17:13
  • Boa Laercio...

     

    No seu post anterior, acabei conseguindo fazer a query de outra forma, mas mesmo assim, obrigado pela sua ajuda.

     

     

    segunda-feira, 12 de janeiro de 2009 17:15
  • Olá Gustavo

     

    Estou utilizando SQL Server 2005. Se vc tiver mais alguma solução diferente da solução do Laercio, ficarei grato

     

    segunda-feira, 12 de janeiro de 2009 17:17
  • Boa Tarde Carlos

     

    Conheço mais quatro maneiras diferentes de se fazer isso no SQL Server 2005.

    Hoje está um dia conturbado e estou com dificuldades de responder Threads. Postarei a solução quando puder (ainda hoje). Se você não puder aguardar, sugiro assistir o Webcast

     

    [ ]s,

     

    Gustavo Maia Aguiar

    http://gustavomaiaaguiar.spaces.live.com

     

    segunda-feira, 12 de janeiro de 2009 18:45
  • Sem problemas Gustavo, estou no aguardo

     

    Obrigado

     

    segunda-feira, 12 de janeiro de 2009 19:22
  • Olá Carlos Wakamatsu,

     

    Conforme prometido segue uma versão simplificada (adapte-a):

     

    Code Snippet

    -- Cria as tabelas

    CREATE TABLE tabCarros (

    CodCarro INT, Carro VARCHAR(20))

     

    CREATE TABLE tabAcessorios (

    CodAcessorio INT, CodCarro INT, Acessorio VARCHAR(20))

     

    -- Popula alguns registros

    INSERT INTO tabCarros VALUES (1,'Ford Ka')

    INSERT INTO tabCarros VALUES (2,'Ford Ka')

    INSERT INTO tabCarros VALUES (3,'Celta')

    INSERT INTO tabCarros VALUES (4,'Celta')

    INSERT INTO tabCarros VALUES (5,'Celta')

    INSERT INTO tabCarros VALUES (6,'Gol')

    INSERT INTO tabCarros VALUES (7,'Gol')

    INSERT INTO tabCarros VALUES (8,'Gol')

     

    INSERT tabAcessorios VALUES (01,1,'Rodas')

    INSERT tabAcessorios VALUES (02,1,'Radio')

    INSERT tabAcessorios VALUES (03,1,'Limpador Traseiro')

    INSERT tabAcessorios VALUES (04,2,'Rodas')

    INSERT tabAcessorios VALUES (05,2,'Radio')

    INSERT tabAcessorios VALUES (06,3,'Rodas')

    INSERT tabAcessorios VALUES (07,3,'Limpador Traseiro')

    INSERT tabAcessorios VALUES (08,4,'Radio')

    INSERT tabAcessorios VALUES (09,5,'Rodas')

    INSERT tabAcessorios VALUES (10,6,'Rodas')

    INSERT tabAcessorios VALUES (11,6,'Radio')

    INSERT tabAcessorios VALUES (12,6,'Limpador Traseiro')

    INSERT tabAcessorios VALUES (13,8,'Rodas')

    INSERT tabAcessorios VALUES (14,8,'Radio')

    INSERT tabAcessorios VALUES (15,8,'Limpador Traseiro')

    segunda-feira, 12 de janeiro de 2009 21:50
  •  

    -- Tenta retornar todos os carros que tenha rodas, radio e limpador traseiro

    -- O resultado está incorreto, pois, quase todos os carros tem um dos acessórios

    SELECT C.CodCarro, Carro, Acessorio

    FROM tabCarros AS C

    INNER JOIN tabAcessorios AS A ON C.CodCarro = A.CodCarro

    WHERE

    A.Acessorio LIKE '%rodas%' OR

    A.Acessorio LIKE '%radio%' OR

    A.Acessorio LIKE '%limpador traseiro%'

     

    -- Utilizar o AND também não ajuda, pois, um acessório não pode ser roda, radio e limpador traseiro ao mesmo tempo

    SELECT C.CodCarro, Carro, Acessorio

    FROM tabCarros AS C

    INNER JOIN tabAcessorios AS A ON C.CodCarro = A.CodCarro

    WHERE

    A.Acessorio LIKE '%rodas%' AND

    A.Acessorio LIKE '%radio%' AND

    A.Acessorio LIKE '%limpador traseiro%'

    segunda-feira, 12 de janeiro de 2009 21:51
  •  

     

    -- Solução 1

    -- Utiliza a interseção entre os carros que tem roda, radio e limpador traseiro

    ;WITH CarrosEscolhidos AS (

    SELECT CodCarro FROM tabAcessorios WHERE Acessorio LIKE '%rodas%'

    INTERSECT

    SELECT CodCarro FROM tabAcessorios WHERE Acessorio LIKE '%radio%'

    INTERSECT

    SELECT CodCarro FROM tabAcessorios WHERE Acessorio LIKE '%limpador traseiro%')

     

    -- Combina os carros encontrados com seus acessórios

    SELECT C.CodCarro, C.Carro, A.Acessorio

    FROM tabCarros AS C

    INNER JOIN tabAcessorios AS A ON C.CodCarro = A.CodCarro

    WHERE C.CodCarro IN (SELECT CodCarro FROM CarrosEscolhidos)

     

     

    -- Solução 2

    ;WITH CarrosEscolhidos AS (

    SELECT CodCarro FROM tabAcessorios

    WHERE

    Acessorio LIKE '%rodas%' OR

    Acessorio LIKE '%radio%' OR

    Acessorio LIKE '%limpador traseiro%'

    GROUP BY CodCarro

    HAVING COUNT(DISTINCT Acessorio) >= 3)

     

    -- Combina os carros encontrados com seus acessórios

    SELECT C.CodCarro, C.Carro, A.Acessorio

    FROM tabCarros AS C

    INNER JOIN tabAcessorios AS A ON C.CodCarro = A.CodCarro

    WHERE C.CodCarro IN (SELECT CodCarro FROM CarrosEscolhidos)

     

     

    Como eu havia dito existem mais quatro formas de resolver isso. A terceira forma é baseada no pivoteamento e está presente no meu webcast (recomendo assistí-lo). A quarta forma é baseada em lógica reserva e estarei demonstrando-a em uma atualização no meu blog em breve.

     

    Se possível tente não utilizar o LIKE. Mostre uma lista prévia de acessórios e faça com que o usuário os escolha. O LIKE pode inviabilizar algumas das soluções propostas.

     

    [ ]s,

     

    Gustavo Maia Aguiar

    http://gustavomaiaaguiar.spaces.live.com

     

    segunda-feira, 12 de janeiro de 2009 21:51
  • Obrigado Gustavo....Neste momento esta funcionando corretamente a consulta com a opção 2.

     

     

    terça-feira, 13 de janeiro de 2009 10:22