it-swarm-eu.dev

Výpočet procentuálního hodnocení v MS SQL

Jaký je nejlepší způsob, jak vypočítat procentuální hodnocení (např. 90. percentil nebo střední skóre) v MSSQL 2005?

Rád bych si vybral 25., medián a 75. percentil pro jeden sloupec skóre (nejlépe v jediném záznamu, takže můžu kombinovat s průměrem, max a min). Například výstup tabulky může být:

Group  MinScore  MaxScore  AvgScore  pct25  median  pct75
-----  --------  --------  --------  -----  ------  -----
T1     52        96        74        68     76      84
T2     48        98        74        68     75      85
25
Soldarnal

Myslím, že by to bylo nejjednodušší řešení:

SELECT TOP N PERCENT FROM TheTable ORDER BY TheScore DESC

Kde N = (100 - požadovaný percentil). Pokud byste tedy chtěli všechny řádky v 90. percentilu, vybrali byste 10%.

Nejsem si jistý, co tím myslíš "nejlépe v jediném záznamu". Myslíte spočítat, který percentil dané hodnoty pro jeden záznam by spadl do? např. chcete být schopni dělat prohlášení, jako je "vaše skóre je 83, což vás v 91. percentilu." ?

EDIT: OK, pomyslel jsem si na vaši otázku a přišel s touto interpretací. Ptáte se, jak vypočítat mezní skóre pro konkrétní percentil? např. něco takového: být v 90. percentilu musíte mít skóre větší než 78.

Pokud ano, tento dotaz funguje. Nelíbí se mi sub-dotazy, takže v závislosti na tom, pro co to bylo, zřejmě se pokusím najít elegantnější řešení. Vrací však jediný záznam s jedním skóre.

-- Find the minimum score for all scores in the 90th percentile
SELECT Min(subq.TheScore) FROM
(SELECT TOP 10 PERCENT TheScore FROM TheTable
ORDER BY TheScore DESC) AS subq
14
Matt

Podívejte se na příkaz NTILE - dá vám to poměrně snadno!

SELECT  SalesOrderID, 
    OrderQty,
    RowNum = Row_Number() OVER(Order By OrderQty),
    Rnk = RANK() OVER(ORDER BY OrderQty),
    DenseRnk = DENSE_RANK() OVER(ORDER BY OrderQty),
    NTile4  = NTILE(4) OVER(ORDER BY OrderQty)
FROM Sales.SalesOrderDetail 
WHERE SalesOrderID IN (43689, 63181)
9
Elizabeth

Jak na to:

SELECT
  Group,
  75_percentile =  MAX(case when NTILE(4) OVER(ORDER BY score ASC) = 3 then score  else 0 end),
  90_percentile =  MAX(case when NTILE(10) OVER(ORDER BY score  ASC) = 9 then score  else 0 end)     
FROM TheScore
GROUP BY Group
2
Paul

50. percentil je stejný jako medián. Když počítáme další percentil, řekněme 80., třídíme data pro 80 procent dat ve vzestupném pořadí a dalších 20 procent v sestupném pořadí a vezmeme avg dvou středních hodnot.

Pozn .: Medián dotazu je již delší dobu, ale nepamatuje si, kde přesně jsem ho dostal, změnil jsem ho pouze pro výpočet dalších percentilů.

DECLARE @Temp TABLE(Id INT IDENTITY(1,1), DATA DECIMAL(10,5))

INSERT INTO @Temp VALUES(0)
INSERT INTO @Temp VALUES(2)
INSERT INTO @Temp VALUES(8)
INSERT INTO @Temp VALUES(4)
INSERT INTO @Temp VALUES(3)
INSERT INTO @Temp VALUES(6)
INSERT INTO @Temp VALUES(6)
INSERT INTO @Temp VALUES(6) 
INSERT INTO @Temp VALUES(7)
INSERT INTO @Temp VALUES(0)
INSERT INTO @Temp VALUES(1)
INSERT INTO @Temp VALUES(NULL)


--50th percentile or median
SELECT ((
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 50 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA
                ) AS A
        ORDER BY DATA DESC) + 
        (
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 50 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA DESC
                ) AS A
        ORDER BY DATA ASC)) / 2.0


--90th percentile 
SELECT ((
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 90 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA
                ) AS A
        ORDER BY DATA DESC) + 
        (
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 10 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA DESC
                ) AS A
        ORDER BY DATA ASC)) / 2.0


--75th percentile
SELECT ((
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 75 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA
                ) AS A
        ORDER BY DATA DESC) + 
        (
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 25 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA DESC
                ) AS A
        ORDER BY DATA ASC)) / 2.0
1
Kay Aliu

Pracoval jsem na tom trochu víc a tady je to, co jsem přišel:

CREATE PROCEDURE [dbo].[TestGetPercentile]

@percentile as float,
@resultval as float output

AS

BEGIN

WITH scores(score, prev_rank, curr_rank, next_rank) AS (
    SELECT dblScore,
        (ROW_NUMBER() OVER ( ORDER BY dblScore ) - 1.0) / ((SELECT COUNT(*) FROM TestScores) + 1)  [prev_rank],
        (ROW_NUMBER() OVER ( ORDER BY dblScore ) + 0.0) / ((SELECT COUNT(*) FROM TestScores) + 1)  [curr_rank],
        (ROW_NUMBER() OVER ( ORDER BY dblScore ) + 1.0) / ((SELECT COUNT(*) FROM TestScores) + 1)  [next_rank]
    FROM TestScores
)

SELECT @resultval = (
    SELECT TOP 1 
    CASE WHEN t1.score = t2.score
        THEN t1.score
    ELSE
        t1.score + (t2.score - t1.score) * ((@percentile - t1.curr_rank) / (t2.curr_rank - t1.curr_rank))
    END
    FROM scores t1, scores t2
    WHERE (t1.curr_rank = @percentile OR (t1.curr_rank < @percentile AND t1.next_rank > @percentile))
        AND (t2.curr_rank = @percentile OR (t2.curr_rank > @percentile AND t2.prev_rank < @percentile))
)

END

Potom v jiné uložené proceduře:

DECLARE @pct25 float;
DECLARE @pct50 float;
DECLARE @pct75 float;

exec SurveyGetPercentile .25, @pct25 output
exec SurveyGetPercentile .50, @pct50 output
exec SurveyGetPercentile .75, @pct75 output

Select
    min(dblScore) as minScore,
    max(dblScore) as maxScore,
    avg(dblScore) as avgScore,
    @pct25 as percentile25,
    @pct50 as percentile50,
    @pct75 as percentile75
From TestScores

Stále to nedělá to, co hledám. Získáte tak statistiky všech testů; vzhledem k tomu, že bych chtěl, abych si mohl vybrat z tabulky TestScores, která má v sobě několik různých testů, a získat zpět stejné statistiky pro každý jiný test (jako je tomu v tabulce s příklady v mé otázce).

1
Soldarnal

pravděpodobně bych použil server sql 2005 

row_number () over (pořadí podle skóre)/(vyberte počet (*) ze skóre)

nebo něco takového. 

0
karl prosser

udělal bych něco jako:

select @n = count(*) from tbl1
select @median = @n / 2
select @p75 = @n * 3 / 4
select @p90 = @n * 9 / 10

select top 1 score from (select top @median score from tbl1 order by score asc) order by score desc

je to správně?

0
syap