从MySQL数据库中的畅销产品中选择一个好的,更好的,最好的建议

时间:2014-03-16 10:40:13

标签: mysql sql database database-design

我有两张桌子:

ProductsSalesRecords

由此我可以创建一个简单的SQL语句来获得前100名最畅销的产品

SELECT p.item, p.price, COUNT(s.itemId) 
    FROM
    SalesRecords s 
    LEFT JOIN Products p ON p.id=s.itemId
GROUP BY p.id 
ORDER BY COUNT(s.itemId) DESC
LIMIT 100

(顺便说一句,我从SalesRecords中选择然后加入产品,因为我发现它比其他方式快得多 - 我想知道原因,但这不是主要问题!)

希望数据库模式足够清楚,知道发生了什么。我们在ID中有Products列与itemId中的SalesRecords列相关联,加入这些关系的表格,然后按每个产品行出现的次数排序SalesRecords。

我现在想要做的是按价格重新排序该列表并将其拆分为三个部分,然后从三个部分中的每一部分中随机返回两行。

预期结果是:

  • 价格排名前三的两个项目
  • 中间三分之二
  • 第三个底部的两个项目

因此,从最畅销的产品中返回一个好的,更好的,最佳的产品建议。

(在实践中会有其他WHERE clasues等使这更相关,但查询的基础是我需要的)

这可能与SQL有关吗? (MySQL的)

2 个答案:

答案 0 :(得分:0)

我不确定我能得到你想要的东西,但是。

这是你的sql with where子句而不是left join(我希望你没有null)

SELECT p.item, p.price, COUNT(s.itemId) 
FROM SalesRecords AS s,Products AS p
WHERE p.id = s.itemid
GROUP BY p.id
ORDER BY COUNT(s.itemId) DESC
LIMIT 100

因此,上面的查询会返回一个您需要的表。但是您希望按价格排序。

SELECT p.item, p.price 
FROM ( "put your above query here" )
ORDER BY p.price DESC

这将按价格对您的查询进行排序。

我认为我们应该为您的选择操作添加行号。

SET @rownumber := 1; 
SELECT @rownumber := @rownumber + 1 AS rownum , p.item, p.price 
FROM ( "put above query ordered by price" );

这将返回一个表,其中包含100行最佳商品,按价格和此列表的索引排序。现在我想,你想选择前2个最佳(索引1,2),2个中间(索引51,52)和2个底部(索引99,100)

SET @rownumber := 1; 
SELECT @rownumber := @rownumber + 1 AS rownum , p.item, p.price 
FROM ( "put above query ordered by price" );
WHERE rownum = 1 OR rownum = 2 OR rownum = 50 OR row num = 51 ....

这些查询效率非常低,可能会导致表崩溃。您可能想在您的数据库中创建一个WIEV,它是一个派生的虚拟表。这个新表将按行价指数(并经常更新)按价格订购最好的100个项目。如果你使用select itemid,其中rowindex是1,2,51,...在那个视图中,它会更安全。当然,只有在系统将来重载数据库时才会需要这个。

当您需要高级严格的mysql查询时,VIEW也可以非常方便地使用。

答案 1 :(得分:0)

您明确需要来自前三分之一,中间和底部三分之一的随机行。如果你没有100件商品会怎样?

开始的地方是计算实际返回的项目数量并计算它们。你可以用变量做到这一点。第一次传递后,变量@rn将包含返回值的数量,因此此查询利用了该值。以下内容将价格组分配给每一行:

SELECT ps.*, floor((rn*3 - 1)/ @rn) as pricegroup
FROM (SELECT p.item, p.price, COUNT(s.itemId) as cnt, @rn := @rn + 1 as rn
      FROM SalesRecords s LEFT JOIN
           Products p
           ON p.id=s.itemId CROSS JOIN
           (select @rn := 0) const
      GROUP BY p.id 
      ORDER BY COUNT(s.itemId) DESC
      LIMIT 100
     ) ps;

接下来,您希望从每个中获取两个随机ID。这是MySQL的痛苦。以下是id连接的方法:

SELECT floor((rn*3 - 1)/ @rn) as pricegroup,
       substring_index(group_concat(p.item order by rand()), ',', 2) as randitems
FROM (SELECT p.item, p.price, COUNT(s.itemId) as cnt, @rn := @rn + 1 as rn
      FROM SalesRecords s LEFT JOIN
           Products p
           ON p.id=s.itemId CROSS JOIN
           (select @rn := 0) const
      GROUP BY p.id 
      ORDER BY COUNT(s.itemId) DESC
      LIMIT 100
     ) ps
GROUP BY floor((rn*3 - 1)/ @rn);

最后,我们可以加入回来获取更全面的信息:

SELECT p.*, pricegroup
FROM (SELECT floor((rn*3 - 1)/ @rn) as pricegroup,
             substring_index(group_concat(p.item order by rand()), ',', 2) as randitems
      FROM (SELECT p.item, p.price, COUNT(s.itemId) as cnt, @rn := @rn + 1 as rn
            FROM SalesRecords s LEFT JOIN
                 Products p
                 ON p.id=s.itemId CROSS JOIN
                 (select @rn := 0) const
            GROUP BY p.id 
            ORDER BY COUNT(s.itemId) DESC
            LIMIT 100
           ) ps
      GROUP BY floor((rn*3 - 1)/ @rn)
     ) pg join
     products p
     on find_in_set(p.item, pg.randitems);

不建议对大型数据执行这些操作。但是,您将数据限制为100行,因此性能应该非常合理。