2013-06-20 118 views
2

用户我有以下查询将返回在表中交易的用户谁有$ 100和$ 200SQL组按编号在范围内

SELECT COUNT(users.id) 
FROM transactions 
LEFT JOIN users ON users.id = transactions.user_id 
WHERE transactions.amount > 100 AND transactions.amount < 200 

上面的查询之间赚了数返回下面的正确的结果:

COUNT(users.id) 
559    

我想扩展它,以便查询可以按以下格式返回数据:

COUNT(users.id) :  amount 
1678    :  0-100 
559    :  100-200 
13     :  200-300 

我该怎么做?

+0

为什么不只是三个查询? –

+0

这只是一个简单的例子,实际上我需要更多的范围。 –

回答

2

您可以使用聚合函数内部的CASE表达式,将得到的结果列:

SELECT 
    COUNT(case when amount >= 0 and amount <= 100 then users.id end) Amt0_100, 
    COUNT(case when amount >= 101 and amount <= 200 then users.id end) Amt101_200, 
    COUNT(case when amount >= 201 and amount <= 300 then users.id end) Amt201_300 
FROM transactions 
LEFT JOIN users 
    ON users.id = transactions.user_id; 

SQL Fiddle with Demo

你会发现,我改变了范围从0到100,101 -200,201-300,否则你将有用户id在100,200的值上计数两次。

如果你想在每行的值,那么你可以使用:

select count(u.id), 
    CASE 
    WHEN amount >=0 and amount <=100 THEN '0-100' 
    WHEN amount >=101 and amount <=200 THEN '101-200' 
    WHEN amount >=201 and amount <=300 THEN '101-300' 
    END Amount 
from transactions t 
left join users u 
    on u.id = t.user_id 
group by 
    CASE 
    WHEN amount >=0 and amount <=100 THEN '0-100' 
    WHEN amount >=101 and amount <=200 THEN '101-200' 
    WHEN amount >=201 and amount <=300 THEN '101-300' 
    END 

SQL Fiddle with Demo

但如果你有,你需要在计算计数许多范围,那么你可能想考虑范围创建表,类似于以下内容:

create table report_range 
(
    start_range int, 
    end_range int 
); 

insert into report_range values 
(0, 100), 
(101, 200), 
(201, 300); 

然后你就可以使用此表加入到当前的表和组由RAN ge值:

select count(u.id) Total, concat(start_range, '-', end_range) amount 
from transactions t 
left join users u 
    on u.id = t.user_id 
left join report_range r 
    on t.amount >= r.start_range 
    and t.amount<= r.end_range 
group by concat(start_range, '-', end_range); 

参见SQL Fiddle with Demo

如果你不想创建范围的新表,那么你可以随时使用派生表来获得相同的结果:

select count(u.id) Total, concat(start_range, '-', end_range) amount 
from transactions t 
left join users u 
    on u.id = t.user_id 
left join 
(
    select 0 start_range, 100 end_range union all 
    select 101 start_range, 200 end_range union all 
    select 201 start_range, 300 end_range 
) r 
    on t.amount >= r.start_range 
    and t.amount<= r.end_range 
group by concat(start_range, '-', end_range); 

SQL Fiddle with Demo

+0

像这样的桶是EXCEL可以帮助编写sql的地方。 –

+0

这真的很不错,在速度方面它与使用多个查询相比如何? –

+0

此外,您是否需要使用关键字“as”? –

2

一种方式做这将是在你的组中使用case/when语句。

SELECT 
-- NB this must match your group by statement exactly 
-- otherwise you will get an error 
CASE 
    WHEN amount <= 100 
    THEN '0-100' 
    WHEN amount <= 200 
    THEN '100-200' 
    ELSE '201+' 
END Amount, 
COUNT(*) 
FROM 
    transactions 
GROUP BY 
CASE 
    WHEN amount <= 100 
    THEN '0-100' 
    WHEN amount <= 200 
    THEN '100-200' 
    ELSE '201+' 
END 

如果你打算使用分组别处,这可能是有道理将其定义为一个标量函数(它也将寻找更清洁)

例如

SELECT 
AmountGrouping(amount), 
COUNT(*) 
FROM 
transactions 
GROUP BY 
AmountGrouping(amount) 

如果你想成为完全通用:

SELECT 
    concat(((amount DIV 100) * 100),'-',(((amount DIV 100) + 1) * 100)) AmountGroup, 
    COUNT(*) 
FROM 
    transactions 
GROUP BY 
    AmountGroup 

Sql Fiddle

+0

请注意,这比其他答案更具通用性,因为您可以定义您的函数来执行任何类型的分组,并且您将获得行而不是列 –

+0

我实际上正在处理更新我的一般性答案,使用范围表或派生表。 – Taryn

+0

图我会证明它;) –

0

比尔博,我尝试勇于创新,找到了一个非常好的解决方案[对于那些谁喜欢数学(像我一样) ]
当MySQL整数除法运算符解决我们的问题时,总是令人惊讶。

DROP SCHEMA IF EXISTS `stackoverflow3`; 
CREATE SCHEMA `stackoverflow3`; 
USE `stackoverflow3`; 

CREATE TABLE users (
    id INT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, 
    name VARCHAR(25) NOT NULL DEFAULT "-"); 

CREATE TABLE transactions(
    id INT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, 
    user_id INT UNSIGNED NOT NULL, 
    amount INT UNSIGNED DEFAULT 0, 
    FOREIGN KEY (user_id) REFERENCES users (id)); 

INSERT users() VALUES(),(),(); 
INSERT transactions (user_id,amount) 
    VALUES (1,120),(2,270),(3, 350), 
    (2,500), (1,599), (1,550), (3,10), 
    (3,20), (3,30), (3,50), (3,750); 

SELECT 
    COUNT(t.id), 
    CONCAT(
    ((t.amount DIV 100)*100)," to ",((t.amount DIV 100 + 1)*100-1) 
) AS amount_range 
FROM transactions AS t 
GROUP BY amount_range; 

等待您的问题,巴金斯先生。

+0

你的界限是正确的(例如0-99) –