SQL Server How do I create an SQL query that groups by value ranges

c9qzyr3d  于 2024-01-05  发布在  其他
关注(0)|答案(8)|浏览(137)

I would like to create a sql query that reports the percentage of results in a particular range. for instance

20% of the values between 10 to 20

40% of the values between 20 to 32.5

Server - MSSQL

up9lanfz

up9lanfz1#

  1. GROUP BY CASE
  2. WHEN VALUE >= 10 AND VALUE <= 20 THEN '20%'
  3. WHEN VALUE > 20 AND VALUE <= 32.5 THEN '40%' ELSE '0' END

You need to cover all possible values, hence the ELSE 0. You'll probably want to do something a little different there, but it should give you a start.

Based on Joel Gauvreau's comment:

  1. SUM(CASE WHEN VALUE >=10 AND VALUE <= 20 THEN 1.0 ELSE 0.0 END) / COUNT(*),
  2. SUM(CASE WHEN VALUE > 20 AND VALUE <= 32.5 THEN 1.0 ELSE 0.0 END) / COUNT(*)

Or at the end of the query use the COMPUTE statement.

mccptt67

mccptt672#

  1. SELECT B.Description, Total = COUNT(*) / CONVERT(money, (SELECT COUNT(*) FROM Target T2))
  2. FROM Target T
  3. JOIN (
  4. SELECT Description = '0 to 10', LBound = 0, UBound = 10
  5. UNION ALL
  6. SELECT Description = '10 to 20', LBound = 10, UBound = 20
  7. ) B ON T.Value >= LBound AND T.Value < B.UBound
  8. GROUP BY B.Description
w46czmvw

w46czmvw3#

This will get you the count per range, you can easily determine the percentage from there:

  1. declare @ranges table (beginInclusive float, endExclusive float)
  2. insert @ranges (beginInclusive, endExclusive)
  3. select 10, 20
  4. union all select 20, 32.5
  5. select
  6. r.beginInclusive,
  7. r.endExclusive,
  8. count(*)
  9. from t join @ranges on t.RangedValue >= r.beginInclusive and t.RangedValue < r.endExclusive
  10. group by
  11. r.beginInclusive,
  12. r.endExclusive
vnjpjtjt

vnjpjtjt4#

Joel's answer seems the best way to me. Posting to explain the query, and because the answer has an integer division sum/count which will return 1 or 0 instead of a percentage.

For the 20 -> 32.5 range:

  1. select CAST(SUM(
  2. CASE WHEN 20 < field AND field <= 32.5 THEN 1 ELSE 0 END
  3. ) as float) / COUNT(*) * 100.0
  4. from table

The case returns 1 when the value is in range. Because there's no group by clause, the sum adds the result of the case for every row in the table. Convert to float, divide by the number of rows =count(*), and you get the percentage.

You can also write it like:

  1. select SUM(
  2. CASE WHEN 20 < field AND field <= 32.5 THEN 1.0 ELSE 0.0 END
  3. ) / COUNT(*) * 100
  4. from table

Here the CASE will result in a float 1.0 instead of the integer 1.

展开查看全部
idv4meu8

idv4meu85#

I would usually use a subquery and get rangecounts and join in the total to get the percentage. Something like:

  1. SELECT
  2. RangeCount/CNT as Percentage,
  3. Range
  4. FROM
  5. (
  6. SELECT
  7. Count(*) AS CNT
  8. FROM
  9. SomeTable
  10. ) AS Total
  11. LEFT JOIN
  12. (
  13. SELECT
  14. CASE Val <= 10 then
  15. '0 up to 10'
  16. ELSE
  17. CASE when Val <= 20
  18. '11 to 20'
  19. ELSE
  20. '> 20'
  21. END
  22. END
  23. END AS Range,
  24. COUNT(*) AS RangeCount
  25. FROM
  26. SomeTable
  27. GROUP BY
  28. Range
  29. ) AS RangeTotals
展开查看全部
9njqaruj

9njqaruj6#

  1. Declare @1 as int
  2. Declare @2 as int
  3. Declare @TotalRows as int
  4. set @1 = (Select COUNT(id) FROM dbo.Table_1 WHERE id >= 10 and id <= 20)
  5. set @2 = (Select COUNT(id) FROM dbo.Table_1 WHERE id > 20 AND id <= 32.5);
  6. set @TotalRows = (Select Count(id) from dbo.Table_1);
  7. SELECT CAST(((@1 * 100)/@TotalRows) as nvarchar(32)) + '%', CAST(((@2 * 100)/@TotalRows) as nvarchar(32)) + '%';

Little complicated, but that does work... i suppose...

dbo.Table_1 only has 1 column, 'id' and it is of type int.

pdkcd3nj

pdkcd3nj7#

If it's something that you will be doing regularly, then you can create a table with the ranges and what constitutes those ranges. If not, you can set them up in a table variable or temporary table and join to that. It's basically JohnOpincar's solution, but with a table instead of a subquery.

Also, in your example you list "10 to 20" and "20 to 32.5". Where is a row counted if it's exactly 20? You should probably make sure that your requirements are clear on that point before you deliver the final solution.

polkgigr

polkgigr8#

Readers who found this question after a Google search are most likely, like me, wanting to create a continuous range.

Using the FLOOR() method, you can mathematically create this range with minimal code:

  1. SELECT
  2. COUNT(*) AS patients_in_group,
  3. -- Creates groups in ranges of 10 (60, 70, 80, etc.)
  4. FLOOR(weight/10) * 10 AS weight_group
  5. FROM patients
  6. GROUP BY weight_group

For the specific case of this question, where ranges are not continuous, the previous answer by Joel Coehoorn, using CASES, is the most adequate. It is easy to read and understand.

相关问题