Usuário com melhor resposta
Select em 2 tabelas

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
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.AcessorioFROM
tabCarros AS CINNER
WHERE
C.CodCarro IN (SELECT CodCarro FROM CarrosEscolhidos)-- Solução 2
;
WITH CarrosEscolhidos AS (SELECT
CodCarro FROM tabAcessoriosWHERE
Acessorio
Acessorio
LIKE '%radio%' ORAcessorio
LIKE '%limpador traseiro%'GROUP
BY CodCarroHAVING
COUNT(DISTINCT Acessorio) >= 3)-- Combina os carros encontrados com seus acessórios
SELECT
C.CodCarro, C.Carro, A.AcessorioFROM
tabCarros AS CINNER
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
Todas as Respostas
-
Carlos,
Neste caso, basta um SQL Simples
Neste primeiro SQL, só será retornado os carros com acessórios cadastrados.
Code SnippetSELECT
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 SnippetSELECT
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. -
-
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 SnippetSELECT
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 SnippetSELECT
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)
-
-
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.
-
Calos,
Veja se resolve:
Code SnippetSELECT
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.
-
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.
-
-
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%'>
-
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 SnippetSELECT
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 SnippetSELECT 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. -
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
-
-
-
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
-
-
Olá Carlos Wakamatsu,
Conforme prometido segue uma versão simplificada (adapte-a):
Code Snippet-- Cria as tabelas
CREATE
TABLE tabCarros (CodCarro
CREATE
TABLE tabAcessorios (CodAcessorio
-- 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') -
-- 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, AcessorioFROM
tabCarros AS CINNER
WHERE
A
A
.Acessorio LIKE '%radio%' ORA
.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, AcessorioFROM
tabCarros AS CINNER
WHERE
A
A
.Acessorio LIKE '%radio%' ANDA
.Acessorio LIKE '%limpador traseiro%' -
-- 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.AcessorioFROM
tabCarros AS CINNER
WHERE
C.CodCarro IN (SELECT CodCarro FROM CarrosEscolhidos)-- Solução 2
;
WITH CarrosEscolhidos AS (SELECT
CodCarro FROM tabAcessoriosWHERE
Acessorio
Acessorio
LIKE '%radio%' ORAcessorio
LIKE '%limpador traseiro%'GROUP
BY CodCarroHAVING
COUNT(DISTINCT Acessorio) >= 3)-- Combina os carros encontrados com seus acessórios
SELECT
C.CodCarro, C.Carro, A.AcessorioFROM
tabCarros AS CINNER
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
-