使用mysql按标签名称选择最常查看的项目

时间:2012-06-26 10:32:52

标签: mysql select union

我有2个表:itemsitems_purchasedtag名称和其他描述性信息位于items表格中,每个项目的购买次数保存在items_purchased表格中。这些表在item_id上JOIN

到目前为止,这是我的查询:

(select *, sum(purchaseyesno) as tots from items join items_purchased on items.item_id=items_purchased.item_id where tag = 'History' and deleted!=1 and pub_priv!=1    order by tots desc limit 1)
UNION ALL
(select *, sum(purchaseyesno) as tots from items join items_purchased on items.item_id=items_purchased.item_id where tag = 'Medicine' and deleted!=1 and pub_priv!=1  order by tots desc limit 1)
UNION ALL
(select *, sum(purchaseyesno) as tots from items join items_purchased on items.item_id=items_purchased.item_id where tag = 'Biology' and deleted!=1 and pub_priv!=1  order by tots desc limit 1)
//... more tags (20 in all) would follow

问题是尚未购买包含特定代码的商品,因此查询会引发Column "item_id" cannot be null错误。

这是示例表:

            items              |     items_purchased   |   
  item_id   tag      title     | item_id  purchaseyesno|
    1     Biology  DNA is cool |    1         1        | 
    2     Medicine  Doctors    |    2         1        |  
    3      Law    Laws are cool|    4         1        |    
    4     Biology DNA NOT cool |    1         1        |

示例结果:

item_id   tag       title      tots
  1      Biology   DNA is cool  2
  2      Medicine  Doctors      1
  3       Law   Laws are cool   0

2个问题:

  1. 如果SELECT的结果为NULL,我该如何排除其中一个UNION ALL语句?
  2. 有没有更好的方法来执行此查询,而不是由19 {{1}} s加入的20个select语句?

2 个答案:

答案 0 :(得分:2)

您只想将结果分组 - 没有比这更复杂的了(看不到UNION!):

SELECT   items.*, SUM(purchaseyesno) AS tots
FROM     items JOIN items_purchased USING (item_id)
GROUP BY item_id

<强>更新

根据下面的评论和OP问题的更新,很明显问题比最初的想法更复杂:事实上,它是group-wise maximum问题的一个特例。

但是,必须采用最大值的列本身是另一个分组聚合的结果(purchaseyesno的总和)。

因此,对于子查询,一个人的查询变得相当不优雅:

SELECT *
FROM (
  SELECT   items.*, IFNULL(SUM(purchaseyesno),0) AS tots
  FROM     items LEFT JOIN items_purchased ON folder_id = item_id
  GROUP BY item_id
) AS t NATURAL JOIN (
  SELECT tag, MAX(tots) AS tots
  FROM (
    SELECT   items.*, IFNULL(SUM(purchaseyesno),0) AS tots
    FROM     items LEFT JOIN items_purchased ON folder_id = item_id
    GROUP BY item_id
  ) AS u
  GROUP BY tag
) AS v
GROUP BY tag

sqlfiddle上查看。

这里发生的事情是(使用outer join来包含Law表中没有引用的items_purchased等记录),我们会考虑每个项目的购买总和(物化表u)然后确定具有相同标签名称的物品的最大购买数量。

然后,我们将结果(具体化表格v)加回到第一个表格(u,再次在表格t上实现),同时标记名称和购买次数。

最后,我们再次按tag对结果进行分组,以确保如果具有相同标记的多个项目具有相同数量的最大购买量,则只会不确定地返回其中一个。

答案 1 :(得分:0)

创建主表标记,并将其ID存储在用作名称的表中。 然后下面的查询将是您的问题的解决方案..

select *, sum(purchaseyesno) as tots 
from items left join 
items_purchased ip on (items.item_id=items_purchased.item_id)
inner join tag_table on (tag_table.id=tagId)
where  deleted!=1 and pub_priv!=1 and not items.item_id is null group by tagID