tutorial transact query examples ejemplos sql sql-server tsql

transact - En SQL, ¿cómo se puede "agrupar por" en rangos?



transact sql pdf (14)

Supongamos que tengo una tabla con una columna numérica (digamos "puntuación").

Me gustaría generar una tabla de recuentos, que muestre cuántas veces aparecieron puntajes en cada rango.

Por ejemplo:

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

En este ejemplo, hubo 11 filas con puntajes en el rango de 0 a 9, 14 filas con puntajes en el rango de 10 a 19, y 3 filas con puntajes en el rango de 20-29.

¿Hay alguna manera fácil de configurar esto? ¿Que recomiendas?


Como la columna que se está ordenando ( Range ) es una cadena, se utiliza la clasificación de cadena / palabra en lugar de la clasificación numérica.

Siempre que las cadenas tengan ceros para rellenar las longitudes de los números, la clasificación debería ser semánticamente correcta:

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

Si el rango es mixto, simplemente rellene un cero adicional:

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


En postgres (donde || es el operador de concatenación de cadenas):

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

da:

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


Esto le permitirá no tener que especificar rangos, y debe ser SQL Server independiente. Matemáticas FTW!

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


Haría esto un poco diferente para que se escalara sin tener que definir cada caso:

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

No probado, pero entiendes la idea ...


La respuesta de James Curran fue la más concisa en mi opinión, pero la salida no fue correcta. Para SQL Server, la declaración más simple es la siguiente:

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

Esto supone una tabla temporal #Scores que utilicé para probarla, acabo de completar 100 filas con un número aleatorio entre 0 y 99.


Ninguna de las respuestas más votadas es correcta en SQLServer 2000. Quizás estaban usando una versión diferente.

Aquí están las versiones correctas de ambos en 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

o

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


Tal vez estás preguntando por mantener estas cosas en marcha ...

Por supuesto, invocará una exploración de tabla completa para las consultas y si la tabla que contiene los puntajes que deben ser contados (agregaciones) es grande, es posible que desee una solución de mejor rendimiento, puede crear una tabla secundaria y usar reglas, como on insert , puedes mirarlo.

Sin embargo, no todos los motores RDBMS tienen reglas.


Tratar

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;


Un enfoque alternativo implicaría almacenar los rangos en una tabla, en lugar de incrustarlos en la consulta. Usted terminaría con una tabla, llámala Rangos, que se ve así:

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

Y una consulta que se ve así:

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

Esto significa configurar una tabla, pero sería fácil de mantener cuando cambien los rangos deseados. ¡No es necesario cambiar el código!


Veo respuestas aquí que no funcionarán en la sintaxis de SQL Server. Yo usaría:

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

EDITAR: ver comentarios


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


declare @RangeWidth int set @RangeWidth = 10 select Floor(Score/@RangeWidth) as LowerBound, Floor(Score/@RangeWidth)+@RangeWidth as UpperBound, Count(*) From ScoreTable group by Floor(Score/@RangeWidth)


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


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

Asegúrese de utilizar una palabra que no sea ''rango'' si está en MySQL, o obtendrá un error al ejecutar el ejemplo anterior.