此解决方案是对另一个 SO 解决方案的改编,感谢 RageZ 找到此相关/类似问题。
笔记
这个解决方案对于 Justin 的用例来说似乎是令人满意的。根据您的用例,您可能希望在这篇文章中查看 Bill Karwin 或 David Andres 的解决方案。比尔的解决方案有我的投票!看看为什么,因为我将两个查询放在一起;-)
我的解决方案的好处是它为每个 category_id 返回一条记录(来自项目表的信息是“汇总”的)。我的解决方案的主要缺点是它缺乏可读性,并且随着所需行数的增加(比如每个类别有 6 行而不是 6 行),它的复杂性也在增加。此外,随着项目表中行数的增长,它可能会稍微慢一些。(无论如何,如果项目表中符合条件的行数较少,所有解决方案的性能都会更好,因此建议定期删除或移动较旧的项目和/或引入一个标志以帮助 SQL 尽早过滤掉行)
第一次尝试(没用!!!)...
这种方法的问题在于,子查询会[理所当然,但对我们不利]会根据自连接定义的笛卡尔积产生很多行......
SELECT id, CategoryName(?), tblFourImages.*
FROM category
JOIN (
SELECT i1.category_id, i1.image as Image1, i2.image AS Image2, i3.image AS Image3, i4.image AS Image4
FROM item AS i1
LEFT JOIN item AS i2 ON i1.category_id = i2.category_id AND i1.date_listed > i2.date_listed
LEFT JOIN item AS i3 ON i2.category_id = i3.category_id AND i2.date_listed > i3.date_listed
LEFT JOIN item AS i4 ON i3.category_id = i4.category_id AND i3.date_listed > i4.date_listed
) AS tblFourImages ON tblFourImages.category_id = category.id
--WHERE here_some_addtional l criteria if needed
ORDER BY id ASC;
第二次尝试。 (工作正常!)
为子查询添加了 WHERE 子句,强制列出的日期分别为 i1、i2、i3 等的最新、第二晚、第三晚等(并且还允许在少于 4 个项目时为空情况给定的类别 ID)。还添加了不相关的过滤器子句,以防止显示“已售出”的条目或没有图像的条目(添加要求)
此逻辑假设没有重复的日期列出值(对于给定的 category_id)。这种情况否则会创建重复的行。 实际上,列出的日期的这种使用是比尔解决方案中定义/要求的单调递增主键的使用。
SELECT id, CategoryName, tblFourImages.*
FROM category
JOIN (
SELECT i1.category_id, i1.image as Image1, i2.image AS Image2, i3.image AS Image3, i4.image AS Image4, i4.date_listed
FROM item AS i1
LEFT JOIN item AS i2 ON i1.category_id = i2.category_id AND i1.date_listed > i2.date_listed AND i2.sold = FALSE AND i2.image IS NOT NULL
AND i1.sold = FALSE AND i1.image IS NOT NULL
LEFT JOIN item AS i3 ON i2.category_id = i3.category_id AND i2.date_listed > i3.date_listed AND i3.sold = FALSE AND i3.image IS NOT NULL
LEFT JOIN item AS i4 ON i3.category_id = i4.category_id AND i3.date_listed > i4.date_listed AND i4.sold = FALSE AND i4.image IS NOT NULL
WHERE NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i1.date_listed)
AND (i2.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i2.date_listed AND date_listed <> i1.date_listed)))
AND (i3.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i3.date_listed AND date_listed <> i1.date_listed AND date_listed <> i2.date_listed)))
AND (i4.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i4.date_listed AND date_listed <> i1.date_listed AND date_listed <> i2.date_listed AND date_listed <> i3.date_listed)))
) AS tblFourImages ON tblFourImages.category_id = category.id
--WHERE --
ORDER BY id ASC;
现在...比较以下我引入 item_id 键并使用比尔的解决方案将这些列表提供给“外部”查询的地方。你可以看到为什么比尔的方法更好......
SELECT id, CategoryName, image, date_listed, item_id
FROM item I
LEFT OUTER JOIN category C ON C.id = I.category_id
WHERE I.item_id IN
(
SELECT i1.item_id
FROM item i1
LEFT OUTER JOIN item i2
ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id
AND i1.sold = 'N' AND i2.sold = 'N'
AND i1.image <> '' AND i2.image <> ''
)
GROUP BY i1.item_id
HAVING COUNT(*) < 4
)
ORDER BY category_id, item_id DESC