2010-11-11 71 views
0

我一直在以高效的方式从MySQL数据库中检索数据。MySQL:在HAVING子句之前限制结果集的问题

我有一个很多项目的表。每个项目可以具有状态1,2或3.我想选择具有特定状态的项目,具体取决于其他表格中这些记录的链接。

例子:

  • 的表items与字段:ID,名称,状态,...
  • 的表bought与字段:的itemId,用户id
  • 的表rented与字段:的itemId,用户id

说,我想这对于用户id 123

  1. 所购买的全部记录,具有都是租的状态1
  2. 所有的记录,具有状态1或2
  3. 未购买或租借的所有记录,其状态3

我的选择查询现在看起来是这样的:

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子句中的变量。并且由于项目表中没有列rentedbought,所以这将不起作用。

我也尝试使用用户定义的变量,但这并没有工作,要么:

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

是最终的结果集输出'bought'和'rented'列必要的,或者是他们那里只是为了利用列别名? – 2010-11-11 02:55:43

+0

他们也有必要以后区分项目。 – Alec 2010-11-11 03:44:52

回答

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 
+0

这些子查询应该放在哪里?并且查询中没有用户表,只是对特定用户ID的引用。以及LEFT JOIN将如何限制结果集? – Alec 2010-11-11 03:47:39

+0

啊,检查!我明白你的意思了。玩了一段时间,它似乎工作!谢谢。 – Alec 2010-11-11 16:53:34