2013-06-20 48 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) –