SQL: Declaração para mostrar um registro filho por pai em um relacionamento um-para-muitos
-
23-08-2019 - |
Pergunta
Eu tenho 2 tabelas, uma tabela de produtos e uma tabela de imagem. Os produtos podem ter uma imagem mais de 1 por registro. Eu preciso de uma instrução SQL que irá listar imagem 1 por produto, em vez de todas as imagens por produto.
A reduzida exemplo do meu esforço atual é:
SELECT Product.RefCode, Img.ImgPath
FROM Product INNER JOIN (
SELECT ProductImg.ImgPath, ProductImg.PrdFK
FROM ProductImg
LIMIT 0,1) AS Img ON Product.PrdID = Img.PrdFK;
O exemplo acima retorna 0 resultados, no entanto, se eu remover o limite de 0,1 do Sub SELECIONE posso obter uma lista completa de todos os produtos e todas as imagens.
Eu só quero um registro de imagem por registro do produto a ser devolvido.
Eu tenho revisto o código "um programador" para MySQL e funciona bem.
SELECT Product.RefCode,
(Select ProductImg.ImgPath
From ProductImg
Where Product.PrdID = Img.PrdFK LIMIT 0,1) AS ImgPath
FROM Products
Por alguma razão quando se tenta solução "de Bill Karwin", que enviou a carga do servidor por um longo tempo.
Solução
Isso deve funcionar:
SELECT Product.RefCode,
(Select Img.ImgPath
From ProductImg
Where Product.PrdID = Img.PrdFK LIMIT 0,1) As ImgPath
FROM Product
Se você tem uma maneira de determinar qual imagem deve o seleto retorno, então você pode adicionar um onde e talvez um ORDER BY na sub-selecionar.
No exemplo a seguir, nós vamos chegar apenas a mais recente das imagens ativos.
SELECT Product.RefCode,
(Select Img.ImgPath
From ProductImg
Where Product.PrdID = Img.PrdFK
And IsActive = 1
Order By EntryDate Desc LIMIT 0,1) As ImgPath
FROM Product
Editado e corrigido 'Top 1' para 'Limite de 0,1'.
Outras dicas
MySQL tem alguma flexibilidade aqui. Você pode usar GROUP BY para restringir o resultado para uma linha por produto, e, em seguida, o MySQL irá escolher qual imagem arbitrariamente. Na prática, ela tende a ser a imagem que está armazenada fisicamente pela primeira vez no banco de dados, mas você não tem nenhum controle sobre isso.
SELECT p.RefCode, i.ImgPath
FROM Product p INNER JOIN ProductImg i
ON (p.PrdID = i.PrdFK)
GROUP BY p.PrdID;
Se você quer 1 específica imagem por produto, existem maneiras de fazer isso também. Você precisa incluir isso em seus requisitos. : -)
Se você tem uma coluna de identificação na mesa de Imagem, isso deve funcionar (não importa o que o produto SQL ou versão) -
SELECT p.RefCode, i1.ImgPath FROM Product p INNER JOIN ProductImg i1 ON p.PrdId = i1.PrdFk LEFT JOIN ProductImg i2 ON i1.PrdId = i2.PrdId AND i1.ImgId < i2.ImgId WHERE i2.ImgId IS NULL
O que você precisa é uma bandeira na mesa da imagem para especificar se é a principal imagem a ser exibida. Há maneiras de puxar uma imagem arbitrária, mas acho que seria melhor para se certificar de que você puxa a imagem correta.