如何打印最大编号为的商店名称。特定月份和年份的销售额?

时间:2015-12-04 16:42:39

标签: mysql greatest-n-per-group

我的数据库(MySQL数据库)中的两个表如下:

forward[0] = 'a'
forward[1] = 'b'
forward[2] = 'b'
forward[3] = 'a'
forward[4] = '\0'

在“销售”表中,同一商店可以有特定月份的多个销售条目。

现在我要打印最没有的商店的名称。用户输入的月份和年份的条目。

我应该如何以高效可靠的方式实现这一目标?

7 个答案:

答案 0 :(得分:3)

尝试按商店分组,并计算每家商店的交易数量(表A)。然后从表A获得最大数量的交易,您将获得一个数字(例如值B)。接下来,您可以复制用于获取值B的SQL,并将其放在表A中的Having子句中,如下所示:

这是表A

select count(store_id) as sid
from sales
group by store_id

这是值B

select max(sid)
from( select count(store_id) as sid
    from sales
    group by store_id ) t1

这是具有最大交易次数的商店的ID

select store_name, count(store_name)
from sales
group by store_name
having count(store_name) =  (select max(sid)
                                from( select count(store_id) as sid
                                        from sales
                                        group by store_id ) t1)

Yo可以在where子句中添加年和月约束,并将其与stores表连接以获取store_name

select store_name, count(store_name)
from sales, stores
where sales.store_id = stores.store_id
and year(sale_date) = '2015'
and month(sale_date) = '09'
group by store_id, store_name
having count(store_name) =  (select max(sid)
                                from( select count(store_id) as sid
                                        from sales
                                        where year(sale_date) = '2015'
                                        and month(sale_date) = '09'
                                        group by store_id ) t1)

请注意,根据销售数量重新安排商店并将解决方案限制在第一个注册表的其他解决方案可能是错误的,因为可能有多个商店具有相同数量的交易 。此查询将返回具有该销售数量的所有商店。

Pd:你可以尝试这个解决方案here

此致

答案 1 :(得分:2)

在线演示

查看我的fiddle

结果查询

SELECT s.*, COUNT(sl.store_id) AS number_of_sales        
FROM stores s
  JOIN sales sl ON 
    s.store_id = sl.store_id 
    AND sl.sale_date BETWEEN '2015-09-01' AND '2015-09-30'
GROUP BY s.store_id
ORDER BY number_of_sales DESC
LIMIT 1

包含一些注释的总列表

CREATE TABLE stores (
  store_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  store_name VARCHAR(255) NOT NULL
);

CREATE TABLE sales (
  sale_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  store_id INT(11) NOT NULL REFERENCES stores(store_id),
  sale_date DATE NOT NULL,
  sale_amt INT(11) NOT NULL
);

/* add index on sale_date for faster search by dates */
/* if you use myisam, add index on store_id too */
ALTER TABLE sales ADD INDEX (sale_date);

/* test data */
INSERT INTO stores VALUES(1, 'shop1');
INSERT INTO stores VALUES(2, 'shop2');
INSERT INTO stores VALUES(3, 'shop3');

INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (40, 2, '2015-09-22', 31);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (41, 2, '2015-09-30', 74);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (42, 1, '2015-01-16', 212);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (43, 3, '2015-09-15', 113);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (44, 1, '2015-09-11', 61);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (45, 1, '2015-09-15', 49);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (46, 1, '2015-05-14', 28);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (47, 3, '2014-12-23', 102);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (48, 1, '2015-09-19', 101);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (49, 2, '2015-09-24', 131);
INSERT INTO sales (sale_id, store_id, sale_date, sale_amt) VALUES (50, 1, '2015-09-13', 155);

/* 
select shop with max number of entries in 2015/April 

Shop1 has 4 sales in 2015/April
Shop2 has 3 sales in 2015/April
Shop3 has 1 sale in 2015/April
*/
SELECT s.*, COUNT(sl.store_id) AS number_of_sales        
FROM stores s
  JOIN sales sl ON 
    s.store_id = sl.store_id 
    AND sl.sale_date BETWEEN '2015-09-01' AND '2015-09-30'
GROUP BY s.store_id
ORDER BY number_of_sales DESC
LIMIT 1

说明

首先,查询会为每个商店选择销售,这些商店的销售额实际为JOIN

第二,我们通过GROUP BY计算销售foreach商店的数量。

第三,我们按照条目数desc排序(通过ORDER BY)分组结果,并选择一个(通过LIMIT)最高值。

P.S。您可以将上述查询与其他答案的查询进行比较,并告诉我们结果:)

基准

我生产了1000家商店和1000万销售额。在localhost Windows NT上测试,5.5.25a-log - MySQL社区服务器(GPL),默认为my-large.ini配置。表类型为INNODB。

使用SQL_NO_CACHE指令从3次启动中获得平均时间。

an3sarmiento的解决方案会引发语法错误。

select SQL_NO_CACHE store_id, count(*)
from sales
group by store_id
having count(*) = (select max(count(*))
                    from sales
                    group by store_id)
  

# 1111 - 无效使用群组功能

zedfoxus的解决方案执行8.8秒

select SQL_NO_CACHE store_name
from stores st
inner join sales sa on st.store_id = sa.store_id
where year(sale_date) = '2015'
  and month(sale_date) = '09'
group by store_name
order by count(*) desc

limit 1;

此解决方案的特别说明。如果不同的商店名称相同,则其结果将分组为一个商店的结果(因为group by store_name声明)。

Innos Heo的解决方案引发了语法错误

SELECT SQL_NO_CACHE store_name
FROM stores
    INNER JOIN
    (
        SELECT store_id, COUNT(*) AS cnt
        FROM sales
        GROUP BY store_id
        WHERE sale_date BETWEEN '2015-09-01' AND '2015-09-30'
        ORDER BY cnt
        LIMIT 1
    ) max_sales ON stores.store_id = max_sales.store_id;
  

#1064 - 您的SQL语法出错;检查与MySQL服务器版本对应的手册,以获得正确的语法   附近' WHERE sale_date BETWEEN' 2015-09-01' AND' 2015-09-30'           按顺序排序        '在第8行

我上面提到的解决方案执行了143秒。

但它会剔除同名商店,但不同的商品。

结语

如果您使用大数据并希望获得最佳性能,则需要使用precalc。构建数据库级别。首先会存储所有数据,第二个会回复用户'查询。

例如,您可以创建表格,该表格按年份和月份存储每个商店的销售额。为了使数据保持最新,您可以使用触发器。

如果你的数据不是很大,那么就不要在优化中发挥作用。一切都是用例。

答案 2 :(得分:1)

请尝试此查询。我已经通过创建您的演示数据库来检查它。

 SELECT COUNT(*) AS total, 
           st.store_name, sl.store_id, sl.sale_date, sl.sale_amt, 
           YEAR(sl.sale_date) as year, 
           MONTH(sl.sale_date) as month 
    FROM stores AS st 
    JOIN sales AS sl ON st.store_id = sl.store_id 
    WHERE YEAR(sl.sale_date)='2015' and MONTH(sl.sale_date)='12' 
    GROUP BY st.store_id
    ORDER BY total
    DESC LIMIT 1

答案 3 :(得分:0)

你可以试一试:

select store_name
from stores st
inner join sales sa on st.store_id = sa.store_id
where year(sale_date) = <year entered by user>
  and month(sale_date) = <month entered by user>
group by store_name
order by count(*) desc
limit 1;

您可能会因为创建一对覆盖索引而受益:

create index idx_stores_id_name on stores(store_id, store_name);
create index idx_sales_storeid_saledate on sales (store_id, sale_date);

答案 4 :(得分:0)

要有效地获得它,请在INNER JOIN之前获得前1名store_id。这可以防止加入一对多关系。

SELECT store_name
FROM stores
    INNER JOIN
    (
        SELECT store_id, COUNT(*) AS cnt
        FROM sales
        WHERE sale_date BETWEEN '2015-09-01' AND '2015-09-30'
        GROUP BY store_id
        ORDER BY cnt DESC
        LIMIT 1
    ) max_sales ON stores.store_id = max_sales.store_id;

假设,至少存在以下索引:

CREATE INDEX idx1 ON sales (sale_date, store_id);

答案 5 :(得分:0)

您可以使用此查询

SELECT store_name
FROM stores
WHERE store_id = (
    SELECT store_id
    FROM sales
    WHERE YEAR(sale_date) = '<year value>'
    AND MONTH(sale_date) = '<month value>'
    GROUP BY store_id
    ORDER BY COUNT(*) DESC
    LIMIT 1
)

这将提供所需的结果,如果数据在数据库表中更多,它将比连接更快。

答案 6 :(得分:0)

问题不是SUM(sale_amt)吗?

SELECT  
      ( SELECT  store_name
            FROM  Stores
            WHERE  store_id = s.store_id 
      ) AS StoreName
    FROM  Sales s
    WHERE  sale_date >= '2015-09-01'
      AND  sale_date  < '2015-09-01' + INTERVAL 1 MONTH
    GROUP BY  store_id
    ORDER BY  SUM(sale_amt) DESC
    LIMIT  1;

(不提供联系)