259

MSDNによると、Median は Transact-SQL の集計関数として使用できません。ただし、この機能を作成できるかどうかを確認したいと思います ( Create Aggregate関数、ユーザー定義関数、またはその他の方法を使用)。

これを行うための最善の方法 (可能であれば) は何でしょうか?集計クエリで中央値 (数値データ型を想定) を計算できるようにしますか?

4

36 に答える 36

238

SQL 2005 以降を使用している場合、これはテーブル内の 1 つの列の単純な中央値計算です。

SELECT
(
 (SELECT MAX(Score) FROM
   (SELECT TOP 50 PERCENT Score FROM Posts ORDER BY Score) AS BottomHalf)
 +
 (SELECT MIN(Score) FROM
   (SELECT TOP 50 PERCENT Score FROM Posts ORDER BY Score DESC) AS TopHalf)
) / 2 AS Median
于 2010-01-08T09:34:05.000 に答える
177

2019 年の更新:この回答を書いてから 10 年間で、より良い結果が得られる可能性がある解決策がさらに発見されました。また、それ以降の SQL Server のリリース (特に SQL 2012) では、中央値の計算に使用できる新しい T-SQL 機能が導入されました。SQL Server のリリースでは、クエリ オプティマイザーも改善されており、さまざまな中央値ソリューションのパフォーマンスに影響を与える可能性があります。ネットネット、私の最初の 2009 年の投稿はまだ問題ありませんが、最新の SQL Server アプリにはより良い解決策があるかもしれません。優れたリソースである 2012 年のこの記事をご覧ください: https://sqlperformance.com/2012/08/t-sql-queries/median

この記事では、少なくともテストした単純なスキーマでは、次のパターンが他のすべての代替案よりもはるかに高速であることがわかりました。このソリューションは、テストした最も遅い ( PERCENTILE_CONT) ソリューションよりも 373 倍高速 (!!!) でした。このトリックには 2 つの個別のクエリが必要であり、すべての場合に実用的ではないことに注意してください。また、SQL 2012 以降も必要です。

DECLARE @c BIGINT = (SELECT COUNT(*) FROM dbo.EvenRows);

SELECT AVG(1.0 * val)
FROM (
    SELECT val FROM dbo.EvenRows
     ORDER BY val
     OFFSET (@c - 1) / 2 ROWS
     FETCH NEXT 1 + (1 - @c % 2) ROWS ONLY
) AS x;

もちろん、2012 年の 1 つのスキーマに対する 1 つのテストで優れた結果が得られたからといって、特に SQL Server 2014 以降を使用している場合は、結果が異なる可能性があります。中央値の計算でパフォーマンスが重要な場合は、その記事で推奨されているいくつかのオプションを試してパフォーマンス テストを行い、スキーマに最適なオプションを見つけたことを確認することを強くお勧めします。

また、この質問に対する他の回答のPERCENTILE_CONT1 つで推奨されている (SQL Server 2012 の新機能) 関数の使用にも特に注意します。それ以来、この格差は 7 年で改善された可能性がありますが、個人的には、パフォーマンスと他のソリューションとの比較を確認するまで、大きなテーブルでこの関数を使用しませんでした。

元の 2009 年の投稿は以下のとおりです。

これを行うには多くの方法があり、パフォーマンスは劇的に異なります。Medians、ROW_NUMBERs、および performanceから、特に最適化されたソリューションの 1 つを次に示します。これは、実行中に生成される実際の I/O に関しては特に最適なソリューションです。他のソリューションよりもコストがかかるように見えますが、実際にははるかに高速です。

このページには、他のソリューションとパフォーマンス テストの詳細についての説明も含まれています。中央値列の値が同じ行が複数ある場合に備えて、一意の列を曖昧さ回避として使用することに注意してください。

すべてのデータベース パフォーマンス シナリオと同様に、常に実際のハードウェアで実際のデータを使用してソリューションをテストするようにしてください。SQL Server のオプティマイザーの変更や環境の特殊性によって、通常は高速なソリューションがいつ遅くなるかはわかりません。

SELECT
   CustomerId,
   AVG(TotalDue)
FROM
(
   SELECT
      CustomerId,
      TotalDue,
      -- SalesOrderId in the ORDER BY is a disambiguator to break ties
      ROW_NUMBER() OVER (
         PARTITION BY CustomerId
         ORDER BY TotalDue ASC, SalesOrderId ASC) AS RowAsc,
      ROW_NUMBER() OVER (
         PARTITION BY CustomerId
         ORDER BY TotalDue DESC, SalesOrderId DESC) AS RowDesc
   FROM Sales.SalesOrderHeader SOH
) x
WHERE
   RowAsc IN (RowDesc, RowDesc - 1, RowDesc + 1)
GROUP BY CustomerId
ORDER BY CustomerId;
于 2009-10-14T17:54:10.793 に答える
91

SQL Server 2012 では、PERCENTILE_CONTを使用する必要があります。

SELECT SalesOrderID, OrderQty,
    PERCENTILE_CONT(0.5) 
        WITHIN GROUP (ORDER BY OrderQty)
        OVER (PARTITION BY SalesOrderID) AS MedianCont
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
ORDER BY SalesOrderID DESC

参照: http://blog.sqlauthority.com/2011/11/20/sql-server-introduction-to-percentile_cont-analytic-functions-introduced-in-sql-server-2012/

于 2012-01-13T06:15:42.117 に答える
21

私の最初の簡単な答えは次のとおりです。

select  max(my_column) as [my_column], quartile
from    (select my_column, ntile(4) over (order by my_column) as [quartile]
         from   my_table) i
--where quartile = 2
group by quartile

これにより、一挙に中央値と四分位範囲が得られます。中央値である行が 1 つだけ必要な場合は、where 句のコメントを外します。

それを説明計画に組み込むと、作業の 60% がデータの並べ替えであり、このような位置に依存する統計を計算する場合、これは避けられません。

以下のコメントで、Robert Ševčík-Robajz からの優れた提案に従うように回答を修正しました。

;with PartitionedData as
  (select my_column, ntile(10) over (order by my_column) as [percentile]
   from   my_table),
MinimaAndMaxima as
  (select  min(my_column) as [low], max(my_column) as [high], percentile
   from    PartitionedData
   group by percentile)
select
  case
    when b.percentile = 10 then cast(b.high as decimal(18,2))
    else cast((a.low + b.high)  as decimal(18,2)) / 2
  end as [value], --b.high, a.low,
  b.percentile
from    MinimaAndMaxima a
  join  MinimaAndMaxima b on (a.percentile -1 = b.percentile) or (a.percentile = 10 and b.percentile = 10)
--where b.percentile = 5

これにより、偶数のデータ項目がある場合に正しい中央値とパーセンタイル値が計算されます。繰り返しますが、パーセンタイル分布全体ではなく中央値のみが必要な場合は、最後の where 句のコメントを外します。

于 2010-06-24T11:42:33.157 に答える
20

さらに良い:

SELECT @Median = AVG(1.0 * val)
FROM
(
    SELECT o.val, rn = ROW_NUMBER() OVER (ORDER BY o.val), c.c
    FROM dbo.EvenRows AS o
    CROSS JOIN (SELECT c = COUNT(*) FROM dbo.EvenRows) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2);

マスター自身から、Itzik Ben-Gan !

于 2012-10-30T22:05:53.633 に答える
9

MS SQL Server 2012 (およびそれ以降) には、並べ替えられた値の特定のパーセンタイルを計算する PERCENTILE_DISC 関数があります。PERCENTILE_DISC (0.5) は中央値を計算します - https://msdn.microsoft.com/en-us/library/hh231327.aspx

于 2016-04-25T13:00:18.517 に答える
4

SQL Server で Create Aggregate 関数を使用する場合は、次のようにします。このようにすると、クリーンなクエリを記述できるという利点があります。このプロセスを適用して、パーセンタイル値をかなり簡単に計算できることに注意してください。

新しい Visual Studio プロジェクトを作成し、ターゲット フレームワークを .NET 3.5 に設定します (これは SQL 2008 用であり、SQL 2012 では異なる場合があります)。次に、クラス ファイルを作成し、次のコードまたは同等の c# コードを挿入します。

Imports Microsoft.SqlServer.Server
Imports System.Data.SqlTypes
Imports System.IO

<Serializable>
<SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToNulls:=True, IsInvariantToDuplicates:=False, _
  IsInvariantToOrder:=True, MaxByteSize:=-1, IsNullIfEmpty:=True)>
Public Class Median
  Implements IBinarySerialize
  Private _items As List(Of Decimal)

  Public Sub Init()
    _items = New List(Of Decimal)()
  End Sub

  Public Sub Accumulate(value As SqlDecimal)
    If Not value.IsNull Then
      _items.Add(value.Value)
    End If
  End Sub

  Public Sub Merge(other As Median)
    If other._items IsNot Nothing Then
      _items.AddRange(other._items)
    End If
  End Sub

  Public Function Terminate() As SqlDecimal
    If _items.Count <> 0 Then
      Dim result As Decimal
      _items = _items.OrderBy(Function(i) i).ToList()
      If _items.Count Mod 2 = 0 Then
        result = ((_items((_items.Count / 2) - 1)) + (_items(_items.Count / 2))) / 2@
      Else
        result = _items((_items.Count - 1) / 2)
      End If

      Return New SqlDecimal(result)
    Else
      Return New SqlDecimal()
    End If
  End Function

  Public Sub Read(r As BinaryReader) Implements IBinarySerialize.Read
    'deserialize it from a string
    Dim list = r.ReadString()
    _items = New List(Of Decimal)

    For Each value In list.Split(","c)
      Dim number As Decimal
      If Decimal.TryParse(value, number) Then
        _items.Add(number)
      End If
    Next

  End Sub

  Public Sub Write(w As BinaryWriter) Implements IBinarySerialize.Write
    'serialize the list to a string
    Dim list = ""

    For Each item In _items
      If list <> "" Then
        list += ","
      End If      
      list += item.ToString()
    Next
    w.Write(list)
  End Sub
End Class

次に、コンパイルして DLL と PDB ファイルを SQL Server マシンにコピーし、SQL Server で次のコマンドを実行します。

CREATE ASSEMBLY CustomAggregate FROM '{path to your DLL}'
WITH PERMISSION_SET=SAFE;
GO

CREATE AGGREGATE Median(@value decimal(9, 3))
RETURNS decimal(9, 3) 
EXTERNAL NAME [CustomAggregate].[{namespace of your DLL}.Median];
GO

次に、次のように中央値を計算するクエリを作成できます。 SELECT dbo.Median(Field) FROM Table

于 2013-05-23T16:29:37.663 に答える
4

シンプル、高速、正確

SELECT x.Amount 
FROM   (SELECT amount, 
               Count(1) OVER (partition BY 'A')        AS TotalRows, 
               Row_number() OVER (ORDER BY Amount ASC) AS AmountOrder 
        FROM   facttransaction ft) x 
WHERE  x.AmountOrder = Round(x.TotalRows / 2.0, 0)  
于 2012-05-08T17:22:36.513 に答える
3

UDFに、次のように記述します。

 Select Top 1 medianSortColumn from Table T
  Where (Select Count(*) from Table
         Where MedianSortColumn <
           (Select Count(*) From Table) / 2)
  Order By medianSortColumn
于 2009-08-27T18:29:49.543 に答える
3

次のクエリは、1 つの列の値のリストから中央値を返します。集計関数として、または集計関数と共に使用することはできませんが、内部選択で WHERE 句を使用してサブクエリとして使用することはできます。

SQL Server 2005 以降:

SELECT TOP 1 value from
(
    SELECT TOP 50 PERCENT value 
    FROM table_name 
    ORDER BY  value
)for_median
ORDER BY value DESC
于 2016-09-08T14:18:08.413 に答える
3

中央値に対するセットベースのソリューションを探しているときに、このページに出くわしました。ここでいくつかの解決策を見た後、私は次のことを思いつきました。希望は助け/働きます。

DECLARE @test TABLE(
    i int identity(1,1),
    id int,
    score float
)

INSERT INTO @test (id,score) VALUES (1,10)
INSERT INTO @test (id,score) VALUES (1,11)
INSERT INTO @test (id,score) VALUES (1,15)
INSERT INTO @test (id,score) VALUES (1,19)
INSERT INTO @test (id,score) VALUES (1,20)

INSERT INTO @test (id,score) VALUES (2,20)
INSERT INTO @test (id,score) VALUES (2,21)
INSERT INTO @test (id,score) VALUES (2,25)
INSERT INTO @test (id,score) VALUES (2,29)
INSERT INTO @test (id,score) VALUES (2,30)

INSERT INTO @test (id,score) VALUES (3,20)
INSERT INTO @test (id,score) VALUES (3,21)
INSERT INTO @test (id,score) VALUES (3,25)
INSERT INTO @test (id,score) VALUES (3,29)

DECLARE @counts TABLE(
    id int,
    cnt int
)

INSERT INTO @counts (
    id,
    cnt
)
SELECT
    id,
    COUNT(*)
FROM
    @test
GROUP BY
    id

SELECT
    drv.id,
    drv.start,
    AVG(t.score)
FROM
    (
        SELECT
            MIN(t.i)-1 AS start,
            t.id
        FROM
            @test t
        GROUP BY
            t.id
    ) drv
    INNER JOIN @test t ON drv.id = t.id
    INNER JOIN @counts c ON t.id = c.id
WHERE
    t.i = ((c.cnt+1)/2)+drv.start
    OR (
        t.i = (((c.cnt+1)%2) * ((c.cnt+2)/2))+drv.start
        AND ((c.cnt+1)%2) * ((c.cnt+2)/2) <> 0
    )
GROUP BY
    drv.id,
    drv.start
于 2011-05-23T21:46:04.363 に答える
2

上記のジャスティンの例は非常に優れています。しかし、その主キーの必要性は非常に明確に述べる必要があります。キーなしでコードが公開されているのを見たことがありますが、結果は良くありません。

Percentile_Cont についての不満は、データセットから実際の値が得られないということです。データセットから実際の値である「中央値」を取得するには、Percentile_Disc を使用します。

SELECT SalesOrderID, OrderQty,
    PERCENTILE_DISC(0.5) 
        WITHIN GROUP (ORDER BY OrderQty)
        OVER (PARTITION BY SalesOrderID) AS MedianCont
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
ORDER BY SalesOrderID DESC
于 2014-09-06T17:51:07.227 に答える
1

上記の Jeff Atwood の回答に基づいて、GROUP BY と相関サブクエリを使用して、各グループの中央値を取得します。

SELECT TestID, 
(
 (SELECT MAX(Score) FROM
   (SELECT TOP 50 PERCENT Score FROM Posts WHERE TestID = Posts_parent.TestID ORDER BY Score) AS BottomHalf)
 +
 (SELECT MIN(Score) FROM
   (SELECT TOP 50 PERCENT Score FROM Posts WHERE TestID = Posts_parent.TestID ORDER BY Score DESC) AS TopHalf)
) / 2 AS MedianScore,
AVG(Score) AS AvgScore, MIN(Score) AS MinScore, MAX(Score) AS MaxScore
FROM Posts_parent
GROUP BY Posts_parent.TestID
于 2016-03-11T18:01:40.310 に答える
1

大規模なデータセットの場合は、次の GIST を試すことができます。

https://gist.github.com/chrisknoll/1b38761ce8c5016ec5b2

セット内にある個別の値 (年齢、生年など) を集計することで機能し、SQL ウィンドウ関数を使用して、クエリで指定したパーセンタイル位置を特定します。

于 2015-06-17T05:03:56.847 に答える
1

ここで、SQL での中央値計算の他のソリューションを参照してください: 「MySQL で中央値を計算する簡単な方法」 (ソリューションはほとんどベンダーに依存しません)。

于 2009-08-27T18:33:13.360 に答える
1

多くの場合、テーブル全体だけでなく、いくつかの ID に関する集計の中央値を計算する必要がある場合があります。つまり、各 ID に多くのレコードがあるテーブルで、各 ID の中央値を計算します。(@gdoron によって編集されたソリューションに基づく: 優れたパフォーマンスと多くの SQL での動作)

SELECT our_id, AVG(1.0 * our_val) as Median
FROM
( SELECT our_id, our_val, 
  COUNT(*) OVER (PARTITION BY our_id) AS cnt,
  ROW_NUMBER() OVER (PARTITION BY our_id ORDER BY our_val) AS rnk
  FROM our_table
) AS x
WHERE rnk IN ((cnt + 1)/2, (cnt + 2)/2) GROUP BY our_id;

それが役に立てば幸い。

于 2017-04-21T22:02:03.677 に答える
0

これはSQL2000で機能します。

DECLARE @testTable TABLE 
( 
    VALUE   INT
)
--INSERT INTO @testTable -- Even Test
--SELECT 3 UNION ALL
--SELECT 5 UNION ALL
--SELECT 7 UNION ALL
--SELECT 12 UNION ALL
--SELECT 13 UNION ALL
--SELECT 14 UNION ALL
--SELECT 21 UNION ALL
--SELECT 23 UNION ALL
--SELECT 23 UNION ALL
--SELECT 23 UNION ALL
--SELECT 23 UNION ALL
--SELECT 29 UNION ALL
--SELECT 40 UNION ALL
--SELECT 56

--
--INSERT INTO @testTable -- Odd Test
--SELECT 3 UNION ALL
--SELECT 5 UNION ALL
--SELECT 7 UNION ALL
--SELECT 12 UNION ALL
--SELECT 13 UNION ALL
--SELECT 14 UNION ALL
--SELECT 21 UNION ALL
--SELECT 23 UNION ALL
--SELECT 23 UNION ALL
--SELECT 23 UNION ALL
--SELECT 23 UNION ALL
--SELECT 29 UNION ALL
--SELECT 39 UNION ALL
--SELECT 40 UNION ALL
--SELECT 56


DECLARE @RowAsc TABLE
(
    ID      INT IDENTITY,
    Amount  INT
)

INSERT INTO @RowAsc
SELECT  VALUE 
FROM    @testTable 
ORDER BY VALUE ASC

SELECT  AVG(amount)
FROM @RowAsc ra
WHERE ra.id IN
(
    SELECT  ID 
    FROM    @RowAsc
    WHERE   ra.id -
    (
        SELECT  MAX(id) / 2.0 
        FROM    @RowAsc
    ) BETWEEN 0 AND 1

)
于 2011-06-13T13:08:41.893 に答える
0

次のソリューションは、これらの仮定の下で機能します。

  • 重複値なし
  • NULL なし

コード:

IF OBJECT_ID('dbo.R', 'U') IS NOT NULL
  DROP TABLE dbo.R

CREATE TABLE R (
    A FLOAT NOT NULL);

INSERT INTO R VALUES (1);
INSERT INTO R VALUES (2);
INSERT INTO R VALUES (3);
INSERT INTO R VALUES (4);
INSERT INTO R VALUES (5);
INSERT INTO R VALUES (6);

-- Returns Median(R)
select SUM(A) / CAST(COUNT(A) AS FLOAT)
from R R1 
where ((select count(A) from R R2 where R1.A > R2.A) = 
      (select count(A) from R R2 where R1.A < R2.A)) OR
      ((select count(A) from R R2 where R1.A > R2.A) + 1 = 
      (select count(A) from R R2 where R1.A < R2.A)) OR
      ((select count(A) from R R2 where R1.A > R2.A) = 
      (select count(A) from R R2 where R1.A < R2.A) + 1) ; 
于 2015-02-17T21:02:04.430 に答える
0

これは私が思いつく限りの簡単な答えです。私のデータでうまくいきました。特定の値を除外したい場合は、内側の select に where 句を追加するだけです。

SELECT TOP 1 
    ValueField AS MedianValue
FROM
    (SELECT TOP(SELECT COUNT(1)/2 FROM tTABLE)
        ValueField
    FROM 
        tTABLE
    ORDER BY 
        ValueField) A
ORDER BY
    ValueField DESC
于 2013-07-16T22:27:44.317 に答える
0
DECLARE @Obs int
DECLARE @RowAsc table
(
ID      INT IDENTITY,
Observation  FLOAT
)
INSERT INTO @RowAsc
SELECT Observations FROM MyTable
ORDER BY 1 
SELECT @Obs=COUNT(*)/2 FROM @RowAsc
SELECT Observation AS Median FROM @RowAsc WHERE ID=@Obs
于 2015-02-25T08:50:45.500 に答える
0

自分で解決策を考えたかったのですが、頭がトリップして途中で落ちてしまいました。うまくいくと思いますが、朝に説明を求めないでください。:P

DECLARE @table AS TABLE
(
    Number int not null
);

insert into @table select 2;
insert into @table select 4;
insert into @table select 9;
insert into @table select 15;
insert into @table select 22;
insert into @table select 26;
insert into @table select 37;
insert into @table select 49;

DECLARE @Count AS INT
SELECT @Count = COUNT(*) FROM @table;

WITH MyResults(RowNo, Number) AS
(
    SELECT RowNo, Number FROM
        (SELECT ROW_NUMBER() OVER (ORDER BY Number) AS RowNo, Number FROM @table) AS Foo
)
SELECT AVG(Number) FROM MyResults WHERE RowNo = (@Count+1)/2 OR RowNo = ((@Count+1)%2) * ((@Count+2)/2)
于 2009-08-27T19:30:15.757 に答える
0
--Create Temp Table to Store Results in
DECLARE @results AS TABLE 
(
    [Month] datetime not null
 ,[Median] int not null
);

--This variable will determine the date
DECLARE @IntDate as int 
set @IntDate = -13


WHILE (@IntDate < 0) 
BEGIN

--Create Temp Table
DECLARE @table AS TABLE 
(
    [Rank] int not null
 ,[Days Open] int not null
);

--Insert records into Temp Table
insert into @table 

SELECT 
    rank() OVER (ORDER BY DATEADD(mm, DATEDIFF(mm, 0, DATEADD(ss, SVR.close_date, '1970')), 0), DATEDIFF(day,DATEADD(ss, SVR.open_date, '1970'),DATEADD(ss, SVR.close_date, '1970')),[SVR].[ref_num]) as [Rank]
 ,DATEDIFF(day,DATEADD(ss, SVR.open_date, '1970'),DATEADD(ss, SVR.close_date, '1970')) as [Days Open]
FROM
 mdbrpt.dbo.View_Request SVR
 LEFT OUTER JOIN dbo.dtv_apps_systems vapp 
 on SVR.category = vapp.persid
 LEFT OUTER JOIN dbo.prob_ctg pctg 
 on SVR.category = pctg.persid
 Left Outer Join [mdbrpt].[dbo].[rootcause] as [Root Cause] 
 on [SVR].[rootcause]=[Root Cause].[id]
 Left Outer Join [mdbrpt].[dbo].[cr_stat] as [Status]
 on [SVR].[status]=[Status].[code]
 LEFT OUTER JOIN [mdbrpt].[dbo].[net_res] as [net] 
 on [net].[id]=SVR.[affected_rc]
WHERE
 SVR.Type IN ('P') 
 AND
 SVR.close_date IS NOT NULL 
 AND
 [Status].[SYM] = 'Closed'
 AND
 SVR.parent is null
 AND
 [Root Cause].[sym] in ( 'RC - Application','RC - Hardware', 'RC - Operational', 'RC - Unknown')
 AND
 (
  [vapp].[appl_name] in ('3PI','Billing Rpts/Files','Collabrent','Reports','STMS','STMS 2','Telco','Comergent','OOM','C3-BAU','C3-DD','DIRECTV','DIRECTV Sales','DIRECTV Self Care','Dealer Website','EI Servlet','Enterprise Integration','ET','ICAN','ODS','SB-SCM','SeeBeyond','Digital Dashboard','IVR','OMS','Order Services','Retail Services','OSCAR','SAP','CTI','RIO','RIO Call Center','RIO Field Services','FSS-RIO3','TAOS','TCS')
 OR
  pctg.sym in ('Systems.Release Health Dashboard.Problem','DTV QA Test.Enterprise Release.Deferred Defect Log')
 AND  
  [Net].[nr_desc] in ('3PI','Billing Rpts/Files','Collabrent','Reports','STMS','STMS 2','Telco','Comergent','OOM','C3-BAU','C3-DD','DIRECTV','DIRECTV Sales','DIRECTV Self Care','Dealer Website','EI Servlet','Enterprise Integration','ET','ICAN','ODS','SB-SCM','SeeBeyond','Digital Dashboard','IVR','OMS','Order Services','Retail Services','OSCAR','SAP','CTI','RIO','RIO Call Center','RIO Field Services','FSS-RIO3','TAOS','TCS')
 )
 AND
 DATEADD(mm, DATEDIFF(mm, 0, DATEADD(ss, SVR.close_date, '1970')), 0) = DATEADD(mm, DATEDIFF(mm,0,DATEADD(mm,@IntDate,getdate())), 0)
ORDER BY [Days Open]



DECLARE @Count AS INT
SELECT @Count = COUNT(*) FROM @table;

WITH MyResults(RowNo, [Days Open]) AS
(
    SELECT RowNo, [Days Open] FROM
        (SELECT ROW_NUMBER() OVER (ORDER BY [Days Open]) AS RowNo, [Days Open] FROM @table) AS Foo
)


insert into @results
SELECT 
 DATEADD(mm, DATEDIFF(mm,0,DATEADD(mm,@IntDate,getdate())), 0) as [Month]
 ,AVG([Days Open])as [Median] FROM MyResults WHERE RowNo = (@Count+1)/2 OR RowNo = ((@Count+1)%2) * ((@Count+2)/2) 


set @IntDate = @IntDate+1
DELETE FROM @table
END

select *
from @results
order by [Month]
于 2009-10-14T17:36:57.023 に答える
0

COUNT 集計を使用すると、最初に行数をカウントし、@cnt という変数に格納できます。次に、数量の順序に基づいて、スキップする行数 (オフセット値) とフィルタリングする行数 (フェッチ値) を指定する OFFSET-FETCH フィルターのパラメーターを計算できます。

スキップする行数は (@cnt - 1) / 2 です。奇数の場合、この計算が正しいことは明らかです。これは、2 で割る前に、最初に 1 つの中間値に対して 1 を減算するためです。

これは、式で使用される除算が整数除算であるため、偶数カウントでも正しく機能します。したがって、偶数から 1 を引くと、奇数の値が残ります。

その奇数値を 2 で除算すると、結果の小数部分 (.5) が切り捨てられます。フェッチする行数は 2 - (@cnt % 2) です。カウントが奇数の場合、モジュロ演算の結果は 1 であり、1 行をフェッチする必要があるという考え方です。カウントが偶数の場合、モジュロ演算の結果は 0 であり、2 行をフェッチする必要があります。モジュロ演算の 1 または 0 の結果を 2 から引くと、それぞれ目的の 1 または 2 が得られます。最後に、量の中央値を計算するには、1 つまたは 2 つの結果量を取得し、次のように入力整数値を数値に変換した後、平均を適用します。

DECLARE @cnt AS INT = (SELECT COUNT(*) FROM [Sales].[production].[stocks]);
SELECT AVG(1.0 * quantity) AS median
FROM ( SELECT quantity
FROM [Sales].[production].[stocks]
ORDER BY quantity
OFFSET (@cnt - 1) / 2 ROWS FETCH NEXT 2 - @cnt % 2 ROWS ONLY ) AS D;
于 2020-06-07T10:47:11.837 に答える
0

従業員テーブルから給与の中央値を取得するには

with cte as (select salary, ROW_NUMBER() over (order by salary asc) as num from employees)

select avg(salary) from cte where num in ((select (count(*)+1)/2 from employees), (select (count(*)+2)/2 from employees));
于 2021-06-08T07:24:00.660 に答える
-2

以下のロジックを試して、中央値を見つけてください。

以下の数字を持つテーブルを考えてみましょう: 1,1,2,3,4,5

中央値は2.5

with tempa as ( select num,count(num) over() as Cnt, row_number() over (num by num) as Rnum from temp), tempb as ( select round(cnt/2) as ref_value from tempa where mod(cnt ,2)<>0 union all select round(cnt/2) from tempa where mod(cnt,2)=0 union all select round(cnt/2+1) from tempa where mod(cnt,2)=0 ) select avg(num) from tempa where rnum in (select * from tempb);

于 2020-01-03T18:15:44.150 に答える