2

MSSQL2008 では、次のように従来の中央値クエリを使用して、共通テーブル式から数値列の中央値を計算しようとしています。

WITH cte AS
(
   SELECT number
   FROM table
) 

SELECT cte.*,
(SELECT 
  (SELECT (   
    (SELECT TOP 1 cte.number  
     FROM     
     (SELECT TOP 50 PERCENT cte.number     
      FROM cte
      ORDER BY cte.number) AS medianSubquery1   
    ORDER BY cte.number DESC)  
    +   
  (SELECT TOP 1 cte.number
   FROM     
    (SELECT TOP 50 PERCENT cte.number    
     FROM cte   
     ORDER BY cte.number DESC) AS medianSubquery2   
   ORDER BY cte.number ASC) ) / 2)) AS median

FROM cte
ORDER BY cte.number

私が得る結果セットは次のとおりです。

NUMBER    MEDIAN
x1        x1
x1        x1
x1        x1
x2        x2
x3        x3

つまり、「中央値」列は、中央値列が「x1」であると予想される場合、「数値」列と同じです。同様の式を使用してモードを計算すると、同じ共通テーブル式に対して正常に機能します。

4

3 に答える 3

3

これを行うには、少し異なる方法を次に示します。

WITH cte AS
(
   SELECT number
   FROM table1
)
SELECT T1.number, T3.median
FROM cte T1, 
(
    SELECT AVG(number) AS median
    FROM
    (
        SELECT number, ROW_NUMBER() OVER(ORDER BY number) AS rn
        FROM cte
    ) T2
    WHERE T2.rn = ((SELECT COUNT(*) FROM table1) + 1) / 2
    OR T2.rn = ((SELECT COUNT(*) FROM table1) + 2) / 2
) T3
于 2010-07-09T22:36:14.390 に答える
1

あなたのクエリの問題は、あなたがやっているということです

SELECT TOP 1 cte.number FROM...

ただし、サブクエリとは相関していません。外部クエリと相関しているため、サブクエリは無関係です。これは、単純にずっと同じ値になってしまう理由を説明しています。cte.(以下のように)を削除すると、CTEの中央値が得られます。これは定数値です。あなたは何をしようとしているのですか?

WITH cte AS
    ( SELECT NUMBER
    FROM master.dbo.spt_values
    WHERE TYPE='p'
    )

SELECT cte.*,
(SELECT 
  (SELECT (   
    (SELECT TOP 1 number  
     FROM     
     (SELECT TOP 50 PERCENT cte.number     
      FROM cte
      ORDER BY cte.number) AS medianSubquery1   
    ORDER BY number DESC)  
    +   
  (SELECT TOP 1 number
   FROM     
    (SELECT TOP 50 PERCENT cte.number    
     FROM cte   
     ORDER BY cte.number DESC) AS medianSubquery2   
   ORDER BY number ASC) ) / 2)) AS median
FROM cte
ORDER BY cte.number

戻り値

NUMBER      median
----------- -----------
0           1023
1           1023
2           1023
3           1023
4           1023
5           1023
6           1023
7           1023
于 2010-07-09T22:32:13.337 に答える
1

これは、Mark Byer の回答をほぼ拡張したものであるため、まったく新しい回答ではありませんが、クエリをさらに簡素化するためのオプションがいくつかあります。

最初のことは、CTE を実際に利用することです。複数の CTE を持つことができるだけでなく、相互に参照することもできます。これを念頭に置いて、最初の結果に基づいて中央値を計算する追加の CTE を作成できます。これにより、中央値の計算がカプセル化され、実際の SELECT は必要なことだけを実行するようになります。ROW_NUMBER() を最初の CTE に移動する必要があることに注意してください。

;WITH cte AS
(
   SELECT number, ROW_NUMBER() OVER(ORDER BY number) AS rn
   FROM table1
),
med AS
(
    SELECT AVG(number) AS median
    FROM cte
    WHERE cte.rn = ((SELECT COUNT(*) FROM cte) + 1) / 2
    OR cte.rn = ((SELECT COUNT(*) FROM cte) + 2) / 2
)
SELECT cte.number, med.median
FROM cte
CROSS JOIN med

さらに複雑さを軽減するために、カスタム CLR Aggregate を使用して中央値を処理することもできます ( http://www.SQLsharp.com/の無料の SQL# ライブラリで提供されているものなど[これは私が作成したものです])。 )。

;WITH cte AS
(
   SELECT number
   FROM table1
),
med AS
(
    SELECT  SQL#.Agg_Median(cte.number) AS median
    FROM    cte
)
SELECT cte.number, med.median
FROM cte
CROSS JOIN med
于 2011-01-21T21:27:51.343 に答える