Pergunta

Isso é muito semelhante a Limite resultados da mesa unida para uma linha, mas estou lutando para fazê -lo funcionar exatamente como eu preciso ...

A estrutura da tabela é muito semelhante:

CREATE TABLE tblProducts (
    intProductID int(11) NULL AUTO_INCREMENT,
    strProductName varchar(255) NULL,
    PRIMARY KEY (intProductID)
);

CREATE TABLE tblProductImages (
    intImageID int(11) NULL AUTO_INCREMENT,
    intProductID int(11) NULL,
    strImageName varchar(255) NULL,
    intOrder int(11) NULL,
    PRIMARY KEY (intImageID)
);

Preencher as mesas com:

INSERT INTO tblProducts (strProductName)
VALUES
('Product #1'), ('Product #2'), ('Product #3');

INSERT INTO tblProductImages (intProductID, strImageName, intOrder) 
VALUES
(1, 'image_for_1.jpg', 1), 
(2, '1st_image_for_2.jpg', 1), 
(2, '2nd_image_for_2.jpg', 2);

Quero fazer uma seleção que retorne todos os três produtos, com imagens apropriadas. Igual a:

intProductID, strProductName, strImageName
1, Product #1, image_for_1.jpg
2, Product #2, 1st_image_for_2.jpg
3, Product #3, NULL

Uma solução simples seria:

SELECT intProductID, strProductName, 
 (SELECT strImageName
  FROM tblProductImages
  WHERE tblProductImages.intProductID = tblProducts.intProductID
  ORDER BY intOrder
  LIMIT 1)
FROM tblProducts

Mas isso falha se eu quiser adicionar e devolver outro campo das TblProductImages (altText, por exemplo)

Eu configurei um violino em http://sqlfiddle.com/#!2/883C5/1

Obrigado

Foi útil?

Solução

Este vai funcionar, mas é bastante feio

select p.intProductId, p.strProductName, pi.strImageName 
from tblProducts p
inner join tblProductImages pi on pi.intProductID = p.intProductId
inner JOIN (select min(intOrder) minOrder, intProductID
           FROM tblProductImages
           GROUP BY intProductID) s
           on s.intProductID = p.intProductID and s.minOrder = pi.intOrder
union
select p.intProductId, p.strProductName, pi.strImageName
from tblProducts p
left join tblProductImages pi on pi.intProductID = p.intProductId
where pi.intProductID is null;

alternativo :

select p.intProductId, p.strProductName, pi.strImageName
from tblProducts p
left join tblProductImages pi on pi.intProductID = p.intProductId
where pi.intProductId is null or pi.IntOrder = (select min(intOrder)
                                                from tblProductImages
                                                where intProductId = pi.intProductId);

Sqlfiddle

Outras dicas

Você precisa usar a agregação (especificamente GROUP BY). Você quer GROUP BY o nome do produto e use um LEFT JOIN para que a imagem não precise existir.

SELECT strProductName, strImageName
FROM tblProducts LEFT JOIN tblProductImages USING (intProductID)
GROUP BY strProductName

Observe que a imagem que é selecionada neste caso é aleatória (embora geralmente esteja em intImageID ordem). Isso pressupõe que a imagem real recuperada não seja importante, desde que esteja associada ao produto especificado.

http://sqlfiddle.com/#!2/1391e6/1

Para a saída exata, pode ser necessário modificar sua instrução de inserção para a Tabela TblProductImages como:

INSERT INTO tblProductImages (intProductID, strImageName, intOrder) VALUES
    (1, 'image_for_1.jpg', 1), (2, '1st_image_for_2.jpg', 1), (3, '2nd_image_for_3.jpg', 2);

E use a instrução SELECT abaixo:

SELECT tP.intProductID, tp.strProductName, tPI.strImageName
FROM tblProducts AS tP 
INNER JOIN tblProductImages AS tPI ON tP.intProductID = tPI.intProductID;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top