2008-10-24 26 views
148

Giả sử tôi có một bảng có cột số (cho phép gọi nó là "điểm").Trong SQL, làm thế nào bạn có thể "nhóm theo" trong phạm vi?

Tôi muốn tạo một bảng đếm, cho biết số lần điểm xuất hiện trong mỗi phạm vi.

Ví dụ:

 
score range | number of occurrences 
------------------------------------- 
    0-9  |  11 
    10-19  |  14 
    20-29  |   3 
    ...  |  ... 

Trong ví dụ này đã có 11 hàng với điểm số nằm trong khoảng từ 0 đến 9, 14 hàng với điểm số nằm trong khoảng từ 10 đến 19, và 3 hàng với điểm số trong trong khoảng 20-29.

Có cách nào dễ dàng để thiết lập tính năng này không? Bạn đề xuất món gì?

Trả lời

114

Cả của câu trả lời bình chọn cao nhất là chính xác trên SQLServer 2000. Có lẽ họ đang sử dụng một phiên bản khác.

Dưới đây là phiên bản chính xác của cả hai trong số họ trên SQLServer 2000.

select t.range as [score range], count(*) as [number of occurences] 
from (
    select case 
    when score between 0 and 9 then ' 0- 9' 
    when score between 10 and 19 then '10-19' 
    else '20-99' end as range 
    from scores) t 
group by t.range 

hoặc

select t.range as [score range], count(*) as [number of occurences] 
from (
     select user_id, 
     case when score >= 0 and score< 10 then '0-9' 
     when score >= 10 and score< 20 then '10-19' 
     else '20-99' end as range 
    from scores) t 
group by t.range 
+0

Tôi có thể tổng hợp một cột khác không (như số nhóm). nói i wana tổng hợp cột học bổng cho mỗi phạm vi điểm. Tôi đã cố gắng, nhưng không nhận được nó ngay –

+0

câu trả lời tốt đẹp @ Tuon Tuffin, tuy nhiên khi bạn có hai phạm vi như 10-20, 100-200, sau đó thứ tự không hoạt động. bạn sẽ có thứ tự như 10-20, 100-200,20-30 vv. Bất kỳ mẹo cho các đơn đặt hàng của? –

+2

@ZoĐó là một chút của một hack nhưng điều này hoạt động: thứ tự của len (t.range), t.range –

5
create table scores (
    user_id int, 
    score int 
) 

select t.range as [score range], count(*) as [number of occurences] 
from (
     select user_id, 
     case when score >= 0 and score < 10 then '0-9' 
     case when score >= 10 and score < 20 then '10-19' 
     ... 
     else '90-99' as range 
    from scores) t 
group by t.range 
+0

Cảm ơn! Tôi đã thử điều này và ý tưởng cơ bản hoạt động rất tốt, mặc dù cú pháp mà tôi đã sử dụng hơi khác một chút. Chỉ cần từ khóa "trường hợp" đầu tiên và sau đó sau điều kiện cuối cùng, trước "phạm vi", bạn cần từ khóa "kết thúc". Ngoài ra, làm việc tuyệt vời, cảm ơn! – Hugh

5
select cast(score/10 as varchar) + '-' + cast(score/10+9 as varchar), 
     count(*) 
from scores 
group by score/10 
+0

Tôi thích điều này, nhưng bạn phải sửa các phạm vi bên ngoài truy vấn nếu bạn định hiển thị nó. – tvanfosson

+0

Trong trường hợp bạn quyết định sửa câu trả lời, bạn cần thay đổi điểm số của bạn/10 trên dòng đầu tiên thành (số điểm/10) * 10 cho cả hai cách khác, bạn sẽ nhận được 3 - 12 thay vì 30-39 vv. đăng bên dưới, bạn có thể thêm đơn đặt hàng để nhận kết quả theo đúng thứ tự. –

19

Trong postgres (nơi || là toán tử nối chuỗi):

select (score/10)*10 || '-' || (score/10)*10+9 as scorerange, count(*) 
from scores 
group by score/10 
order by 1 

cho:

scorerange | count 
------------+------- 
0-9  | 11 
10-19  | 14 
20-29  |  3 
30-39  |  2 
-1

Có lẽ bạn đang hỏi về việc giữ gìn những việc như vậy xảy ra .. .

của đồng bạn sẽ gọi một bảng quét đầy đủ cho các truy vấn và nếu bảng chứa các điểm cần được kiểm tra (tổng hợp) lớn, bạn có thể muốn có giải pháp hoạt động tốt hơn, bạn có thể tạo bảng phụ và sử dụng các quy tắc, chẳng hạn như on insert - bạn có thể nhìn vào nó.

Không phải tất cả các công cụ RDBMS đều có quy tắc!

1
declare @RangeWidth int 

set @RangeWidth = 10 

select 
    Floor(Score/@RangeWidth) as LowerBound, 
    Floor(Score/@RangeWidth)[email protected] as UpperBound, 
    Count(*) 
From 
    ScoreTable 
group by 
    Floor(Score/@RangeWidth) 
28

Tôi thấy câu trả lời ở đây sẽ không hoạt động trong cú pháp của SQL Server. Tôi sẽ sử dụng:

select t.range as [score range], count(*) as [number of occurences] 
from (
    select case 
    when score between 0 and 9 then ' 0-9 ' 
    when score between 10 and 19 then '10-19' 
    when score between 20 and 29 then '20-29' 
    ... 
    else '90-99' end as range 
    from scores) t 
group by t.range 

EDIT: xem ý kiến ​​

+0

Có thể là do phiên bản SQLServer tôi đang sử dụng nhưng để lấy ví dụ của bạn để làm việc (tôi kiểm tra mọi thứ trước khi bỏ phiếu cho họ) Tôi phải di chuyển 'điểm' từ sau 'trường hợp' sang sau mỗi 'khi'. –

+3

Bạn nói đúng và cảm ơn sự điều chỉnh. Rõ ràng khi bạn đặt biến sau từ khóa 'trường hợp', bạn chỉ có thể thực hiện các kết quả khớp chính xác, chứ không phải biểu thức. Tôi học được nhiều từ việc trả lời các câu hỏi khi hỏi họ. :-) –

9

câu trả lời James Curran là ngắn gọn nhất theo ý kiến ​​của tôi, nhưng đầu ra là không đúng. Đối với SQL Server tuyên bố đơn giản nhất là như sau:

SELECT 
    [score range] = CAST((Score/10)*10 AS VARCHAR) + ' - ' + CAST((Score/10)*10+9 AS VARCHAR), 
    [number of occurrences] = COUNT(*) 
FROM #Scores 
GROUP BY Score/10 
ORDER BY Score/10 

này giả định một bảng tạm thời #Scores tôi sử dụng để kiểm tra nó, tôi chỉ cư 100 dòng với số ngẫu nhiên giữa 0 và 99.

+1

Ah ... Có lợi thế là thực sự dành thời gian để tạo bảng. (Tôi đã sử dụng một bảng hiện có với quá ít hàng trong phạm vi quá nhỏ) –

25

Một phương pháp khác sẽ bao gồm lưu trữ các dãy trong một bảng, thay vì nhúng chúng vào truy vấn.Bạn sẽ kết thúc với một bảng, gọi nó là Ranges, trông như thế này:

LowerLimit UpperLimit Range 
0    9   '0-9' 
10   19   '10-19' 
20   29   '20-29' 
30   39   '30-39' 

Và một truy vấn mà trông như thế này:

Select 
    Range as [Score Range], 
    Count(*) as [Number of Occurences] 
from 
    Ranges r inner join Scores s on s.Score between r.LowerLimit and r.UpperLimit 
group by Range 

này có nghĩa là thiết lập một bảng, nhưng nó sẽ dễ duy trì khi phạm vi mong muốn thay đổi. Không cần thay đổi mã!

+0

Tôi đã đặt câu hỏi về Quản trị viên cơ sở dữ liệu [Thiết kế bảng cho dữ liệu được tạo khuôn mẫu bằng cách sử dụng phạm vi nhóm biến số] (http://dba.stackexchange.com/questions/94275/table-design-for-patterned-data-using-variable -bucket-range) không nhận được câu trả lời, nhưng tôi đã thiết kế một hệ thống có phạm vi mà bạn đã đề cập. Yêu câu trả lời này. – OmegaMan

0
select t.blah as [score range], count(*) as [number of occurences] 
from (
    select case 
    when score between 0 and 9 then ' 0-9 ' 
    when score between 10 and 19 then '10-19' 
    when score between 20 and 29 then '20-29' 
    ... 
    else '90-99' end as blah 
    from scores) t 
group by t.blah 

Đảm bảo bạn sử dụng một từ khác với 'dải' nếu bạn đang ở MySQL hoặc bạn sẽ gặp lỗi khi chạy ví dụ trên.

1

Vì cột đang được sắp xếp theo (Range) là một chuỗi, phân loại chuỗi/từ được sử dụng thay vì phân loại số.

Chừng nào các dây có zeros để pad ra số độ dài các phân loại vẫn có ngữ nghĩa chính xác:

SELECT t.range AS ScoreRange, 
     COUNT(*) AS NumberOfOccurrences 
    FROM (SELECT CASE 
        WHEN score BETWEEN 0 AND 9 THEN '00-09' 
        WHEN score BETWEEN 10 AND 19 THEN '10-19' 
        ELSE '20-99' 
       END AS Range 
      FROM Scores) t 
GROUP BY t.Range 

Nếu phạm vi được trộn, chỉ đơn giản là pad thêm zero:

SELECT t.range AS ScoreRange, 
     COUNT(*) AS NumberOfOccurrences 
    FROM (SELECT CASE 
        WHEN score BETWEEN 0 AND 9 THEN '000-009' 
        WHEN score BETWEEN 10 AND 19 THEN '010-019' 
        WHEN score BETWEEN 20 AND 99 THEN '020-099' 
        ELSE '100-999' 
       END AS Range 
      FROM Scores) t 
GROUP BY t.Range 
3

Tôi sẽ làm điều này một chút khác biệt sao cho quy mô đó không phải xác định mọi trường hợp:

select t.range as [score range], count(*) as [number of occurences] 
from (
    select FLOOR(score/10) as range 
    from scores) t 
group by t.range 

Không được thử nghiệm, nhưng bạn có ý tưởng ...

2

Điều này sẽ cho phép bạn không phải chỉ định phạm vi và phải là máy chủ SQL bất khả tri. Toán FTW!

SELECT CONCAT(range,'-',range+9), COUNT(range) 
FROM (
    SELECT 
    score - (score % 10) as range 
    FROM scores 
) 
1

Hãy thử

SELECT (str(range) + "-" + str(range + 9)) AS [Score range], COUNT(score) AS [number of occurances] 
FROM (SELECT score, int(score/10) * 10 AS range FROM scoredata) 
GROUP BY range; 
+3

sẽ rất hữu ích nếu bạn có thể thêm một số giải thích về cách truy vấn của bạn giải quyết vấn đề. –

Các vấn đề liên quan