MySQL возвращает 1 изображение для каждого продукта

StackOverflow https://stackoverflow.com/questions/20353403

  •  25-08-2022
  •  | 
  •  

Вопрос

Это очень похоже на Ограничьте результаты от соединенной таблицы до одной строки, но я изо всех сил пытаюсь заставить его работать точно так, как мне нужно ...

Структура таблицы очень похожа:

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

Заполнить таблицы:

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

Я хочу сделать выбор, который возвращает все 3 продукта с соответствующими изображениями. Похожий на:

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

Простым решением было бы:

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

Но это не удается, если я хочу добавить и вернуть другое поле из TBLProductimages (например, Alttext)

Я настроил скрипку на http://sqlfiddle.com/#!2/883c5/1

Спасибо

Это было полезно?

Решение

Этот будет работать, но довольно уродливый

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;

Альтернатива:

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

Другие советы

Вам нужно использовать агрегацию (в частности GROUP BY) Вы хотите GROUP BY название продукта и используйте LEFT JOIN так что изображение не нужно существовать.

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

Обратите внимание, что изображение, которое выбран в этом случае случайный (Хотя обычно это будет в intImageID заказ). Это предполагает, что фактическое извлеченное изображение не важно, если оно связано с данным продуктом.

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

Для этого точного вывода вам может потребоваться изменить оператор вставки для таблицы TBLProductimages как:

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

И используйте оператор выбора ниже:

SELECT tP.intProductID, tp.strProductName, tPI.strImageName
FROM tblProducts AS tP 
INNER JOIN tblProductImages AS tPI ON tP.intProductID = tPI.intProductID;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top