-2

在 MySQL 数据库中,我有一个包含以下列的购买表:

USERID PURCHASE_AMOUNT  
3         20
9         30
3         5
4         5
1         10
1         5

我想生成这样的报告

SUM_OF_PURCHASES_RANGE NUM_OF_USERS  
0-1                    0
1-5                    1
5-20                   1
20-30                  2

这意味着:有 0 个用户购买了最多 1 个(购买的总和)(含),有 1 个用户购买了 1 到 5 个等...

我应该使用什么查询来生成它?

4

6 回答 6

1

更简单的语法:

SELECT PURCHASE_RANGE , COUNT(*) as NUM_OF_USERS  
FROM 
(
SELECT 
CASE 
    WHEN PURCHASE_AMOUNT <= 1 THEN 1
    WHEN PURCHASE_AMOUNT > 1 AND PURCHASE_AMOUNT <= 5 THEN 5
    WHEN PURCHASE_AMOUNT > 5 AND PURCHASE_AMOUNT <= 10 THEN 10 
    WHEN PURCHASE_AMOUNT > 10 AND PURCHASE_AMOUNT <= 20 THEN 20
    WHEN PURCHASE_AMOUNT > 20 AND PURCHASE_AMOUNT <= 30 THEN 30 END AS PURCHASE_RANGE  
FROM Table1
) AS A
GROUP BY PURCHASE_RANGE
ORDER BY PURCHASE_RANGE

SqlFiddle

于 2013-07-07T20:43:14.080 回答
1

您可以使用 , 创建范围UNION,然后就LEFT JOIN可以获取所有类别;(为您更改所需结果而编辑)

SELECT CONCAT(base.lower,'-',base.upper) PURCHASE_RANGE, COUNT(userid) NUM_OF_USERS
FROM (
  SELECT 0 lower, 1 upper UNION SELECT 2, 5 UNION SELECT 6,20 UNION SELECT 21,30
) base
LEFT JOIN (
  SELECT userid, SUM(purchase_amount) pa FROM purchases GROUP BY userid
) p
  ON p.pa >= base.lower AND p.pa <= base.upper
GROUP BY base.upper

一个用于测试的 SQLfiddle

于 2013-07-07T21:24:18.043 回答
0

尝试这个

    select PURCHASE_RANGE , NUM_OF_USERS 
 from (
 select 1 as PURCHASE_RANGE ,count(*) as  NUM_OF_USERS  from table1 where PURCHASE_AMOUNT between 0 and 1
  union all
 select 5 ,count(*) from table1 where PURCHASE_AMOUNT between 1 and 5
 union all
 select 20 ,count(*) from table1 where PURCHASE_AMOUNT between 6 and 20
  union all
 select 30 ,count(*) from table1 where PURCHASE_AMOUNT between 21 and 30
)t

在这里演示

于 2013-07-07T20:34:55.507 回答
0

如果范围会改变,这可能会更容易。

with ranges(rstart, rfinish) as (
    select  0,  1 union all
    select  2,  5 union all
    select  6, 20 union all
    select 21, 30
), purchases(amount) as (
    select sum(PURCHASE_AMOUNT)
    from <purchases_basetable> -- <-- your tablename goes here
    group by USERID
)
select
    -- concat(case when r.rstart = 0 then 0 else r.rstart-1 end, '-', r.rfinish) as SUM_OF_PURCHASES_RANGE /* op's name for the group */,
    concat(r.rstart, '-', r.rfinish) as SUM_OF_PURCHASES_RANGE /* better name for the group */,
    count(*) as NUM_OF_USERS
from
    purchases as p inner join
    ranges as r
        on p.amount between r.start and r.finish
group by r.rstart, r.rfinish
order by r.rstart, r.rfinish

我不知道mysql查询计划会是什么样子。将查询更改为使用派生表而不是表表达式很简单。(但我还是把它包括在下面。)

您可能还会发现 UNPIVOT 操作在支持它的平台上很有用。

select
    -- concat(case when r.rstart = 0 then 0 else r.rstart-1 end, '-', r.rfinish) as SUM_OF_PURCHASES_RANGE /* op's name for the group */,
    concat(r.rstart, '-', r.rfinish) as SUM_OF_PURCHASES_RANGE /* better name for the group */,

    count(*) as NUM_OF_USERS
from
    (
        select sum(PURCHASE_AMOUNT) as amount
        from <purchases_basetable> -- <-- your tablename goes here
        group by USERID
    ) as p inner join
    (
        select  0 as rstart, 1 as rfinish union all
        select  2,  5 union all
        select  6, 20 union all
        select 21, 30
    ) as r
        on p.amount between r.start and r.finish
group by r.rstart, r.rfinish
order by r.rstart, r.rfinish
于 2013-07-07T20:48:17.537 回答
0

要在行中获取您想要的值,您需要从一个包含您感兴趣的所有值的驱动程序表开始,然后left outer join是数据:

select driver.mina, coalesce(sum(cnt), 0) as Num_Of_Users
from (select 1 as mina, 5 as maxa union all
      select 5, 10 union all
      select 10, 20 union all
      select 20, 30 union all
      select 30, NULL
     ) driver left outer join
     (select purchase_amount, count(*) as cnt
      from purchases
      group by purchase_amount
     ) pa
     on driver.mina >= pa.purchase_amount and
        (pa.purchase_amount < driver.maxa or driver.maxa is null)
group by driver.mina
order by driver.mina

你实际上可以在没有内部的情况下做到这一点group by。在加入之前,这可能会显着减少数据的大小(尤其是在您的示例中)。

我鼓励您在每行中同时包含范围的下限和上限。

于 2013-07-07T20:51:37.567 回答
0

如果您需要性能,有更快的方法来执行此操作(这将执行全表扫描),但试试这个:

SELECT 
SUM(CASE WHEN purchase_amount BETWEEN 0 AND 1 THEN 1 ELSE 0) bucket_0_to_1,
SUM(CASE WHEN purchase_amount BETWEEN 1 AND 5 THEN 1 ELSE 0) bucket_1_to_5,
SUM(CASE WHEN purchase_amount BETWEEN 5 AND 20 THEN 1 ELSE 0) bucket_5_to_20,
SUM(CASE WHEN purchase_amount BETWEEN 20 AND 30 THEN 1 ELSE 0) bucket_20_to_30,
SUM(CASE WHEN purchase_amount > 30 THEN 1 ELSE 0) bucket_over_30, FROM my_table LIMIT 1;
于 2013-07-07T20:39:01.713 回答