我坚持以有效的方式从MySQL数据库中检索数据。
我有一张包含很多物品的桌子。每个项目的状态可以是1,2或3.我想选择具有特定状态的项目,具体取决于其他表格中这些记录的链接。
示例:
items
,其中包含字段:id,name,status,... bought
:itemId,userId rented
:itemId,userId 说我想为userId 123
:
我的选择查询现在看起来像这样:
SELECT
i.id,
i.name,
i.status,
// bought by this user?
SUM(IF(b.userId = 123, 1, 0)) AS bought,
// rented by this user?
SUM(IF(r.userId = 123, 1, 0)) AS rented,
FROM items i
LEFT JOIN bought b
ON b.itemId = i.id
LEFT JOIN rented r
ON r.itemId = r.id
GROUP BY i.id
HAVING
// bought and status 1
(bought > 0 AND status = 1)
// rented and status 1 or 2
OR (rented > 0 AND status IN (1, 2)
// not bought or rented and status 3
OR (bougth = 0 AND rented = 0 AND status = 3)
ORDER BY i.name ASC
问题1
SELECT子句中的SUM部分是否是确定链接到项目的另一个表中是否存在条目的好方法?假设每个用户只有一个条目,总和将为1或0,为我提供所需的信息。但它似乎......某种程度上很奇怪。
问题2
即使这样可行,也存在一个大问题:它基本上检索所有项,然后使用HAVING
子句过滤它们。由于存在相当多的条目,因此查询速度太慢。我正在试图弄清楚如何解决这个问题。
我首先尝试了一个WHERE
子句..但是如何?
...
WHERE
// only items with status 1 if bought or rented
(t.status = 1 AND (bought > 0 OR rented > 0))
// only items with status 2 if rented
OR (t.status = 2 AND rented > 0)
// only items with status 3 if not bought or rented
OR (t.status = 3 AND bought = 0 AND rented = 0)
...
但是你不能使用SELECT
子句中的变量。由于项目表中没有列rented
或bought
,因此无效。
我也尝试使用用户可定义的变量,但这也不起作用:
SELECT
...
@bought := SUM(IF(b.userId = 123, 1, 0)) AS bought,
...
WHERE @bought = ... // does not work
然后我尝试了一个子查询,但我无法使用主查询项id:
...
WHERE
...
// only items with status 2 if rented
OR (
t.status = 2
AND (
SELECT COUNT(r2.userId)
FROM rented r2
WHERE r2.userId = 123
AND r2.itemId = i.itemId // it doesn't recognize i.itemId
) > 0
)
...
有什么想法吗?我还想将所有内容保存在一个查询中。这只是一个简单的例子,但实际的例子相当大。我确信我可以拆分所有内容并使用各种查询来单独收集所有内容,但这只会添加很多更多代码,并且不会使维护更容易。
答案 0 :(得分:1)
使用两个子查询(一个用于买方,一个用于租用),然后将它们连接到主查询中的用户表。
编辑:原谅我的MySQL,已经有一段时间了,但我想到的是:
select i.id, i.name, i.status, ifnull(b.TotalBought,0) AS ItemsBought, ifnull(r.TotalRented,0) AS ItemsRented
FROM items i
LEFT JOIN (select itemid, COUNT(*) AS TotalBought FROM bought WHERE userid=123 GROUP BY itemid) AS b ON b.itemid=i.itemid
LEFT JOIN (select itemid, COUNT(*) AS TotalRented FROM rented WHERE userid=123 GROUP BY itemid) AS r ON r.itemid=i.itemid
WHERE (i.status=1 AND ifnull(b.TotalBought,0)>0)
OR (ifnull(r.TotalRented,0) >0 AND i.status in(1,2)
OR (ifnull(b.TotalBought,0)=0 AND ifnull(r.TotalRented,0) =0 AND i.status=3)
ORDER BY i.name ASC