这个解决方案是从另一个SO的解决方案改编而来,感谢RageZ定位到了相关/类似的问题。
注意
对于Justin的用例,这个解决方案似乎是令人满意的。根据您的用例,您可能想要检查Bill Karwin或David Andres在此帖子中的解决方案。我投票给了Bill的解决方案!看看为什么,因为我将两个查询并排放置;-)
我的解决方案的好处是它返回每个category_id的一个记录(item表中的信息被“卷起”)。我的解决方案的主要缺点是其可读性不足,并且随着所需行数的增加而变得越来越复杂(例如,每个类别需要6行而不是6行)。此外,随着item表中的行数增加,它可能会稍微慢一些。(无论如何,所有解决方案都将在item表中有较少的符合条件的行时执行得更好,因此建议定期删除或移动旧项目和/或引入标志以帮助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
ORDER BY id ASC;
第二次尝试。(工作正常!)
在子查询中添加了WHERE子句,强制列出的日期为i1、i2、i3等的最新日期、第二新日期、第三新日期等(也允许存在少于给定类别ID的4个项目的情况下的空值情况)。还添加了无关的筛选子句,以防止显示“已售出”的条目或没有图像的条目(增加了要求)。
此逻辑假定不存在重复的日期列表值(针对给定的category_id)。否则,这种情况将创建重复的行。实际上,这种使用日期列表的效果就是按照Bill解决方案中定义/要求的单调递增主键的方式。
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
ORDER BY id ASC;
现在... 对比一下以下内容,我介绍了一个item_id键,并使用Bill的解决方案提供这些键的列表给“外部”查询。你可以看到为什么Bill的方法更好...
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