2011-07-05 97 views
0

我試圖找出SQL Server 2008中函數的第95百分位和中位數構建,但我不知道MS爲什麼不給他們提供支持,真的很煩人......我們的工作地點報告非常複雜,想要一個直接的功能,或者可能是一個DLL文件,我可以與SQL服務器組裝,以使用它作爲正常功能。SQL Server 2008中的中位數和第95百分位數? - NHS報告要求

可以任何一個建議。提前致謝。

Reagrds 阿里

回答

1

NTILE功能和MEDIAN閱讀this

+0

Cheers Mladen Prajdic!我將研究這個函數和文章,但如果有人能夠幫助找到一個動態鏈接libraby(dll)將其與SQL服務器組裝起來,使這些功能成爲內置將非常有幫助。再次感謝您的回覆 –

-1

我對NHS的工作以及在這裏是whcih我寫找出正中,MAX的SQL,和第95百分位數 檢查了這一點,並給我發電子郵件[email protected]

WITH kali1 (k1, k2, k3, k4, k5, k6, k7) 
      AS (SELECT MinsInAE , 
         HoursInAE , 
         DaysInAE AS DaysInAE , 
         Month_Name , 
         YearName , 
         InternalNo , 
         ROW_NUMBER() OVER (PARTITION BY Month_Name ORDER BY MinsInAE ASC) AS 'Row Number' 
       FROM  AE.FactAandE 
         INNER JOIN AE.PMI ON AE.FactAandE.FK_PaitentMasterIndex = AE.PMI.PK_Patient 
         INNER JOIN dbo.TimeDimension ON dbo.TimeDimension.DateId = AE.FactAandE.FK_date 
       WHERE YearName = 'Calendar 2010' 
      ), 
     kali2 (k21, k22, k23) 
      AS (SELECT MAX(k7) * 95/100 , 
         k4 , 
         MAX(k7) 
       FROM  kali1 
       GROUP BY k4 
      ), 
     kali3 (k31, k32) 
      AS (SELECT AVG(1.0E * MinsInAE) AS Median , 
         Month_Name 
       FROM  (SELECT MinsInAE , 
            Month_Name , 
            2 
            * ROW_NUMBER() OVER (PARTITION BY Month_Name ORDER BY MinsInAE) 
            - COUNT(*) OVER (PARTITION BY Month_Name) AS y 
          FROM  AE.FactAandE 
            INNER JOIN AE.PMI ON AE.FactAandE.FK_PaitentMasterIndex = AE.PMI.PK_Patient 
            INNER JOIN dbo.TimeDimension ON dbo.TimeDimension.DateId = AE.FactAandE.FK_date 
          WHERE  YearName = 'Calendar 2010' 
         ) AS d 
       WHERE y BETWEEN 0 AND 2 
       GROUP BY Month_Name 
      ), 
     kali4 (k41, k42, k43, k44, k46, k47) 
      AS (SELECT MinsInAE , 
         HoursInAE , 
         DaysInAE AS DaysInAE , 
         Month_Name , 
         YearName , 
         InternalNo 
       FROM  AE.FactAandE 
         INNER JOIN AE.PMI ON AE.FactAandE.FK_PaitentMasterIndex = AE.PMI.PK_Patient 
         INNER JOIN dbo.TimeDimension ON dbo.TimeDimension.DateId = AE.FactAandE.FK_date 
       WHERE YearName = 'Calendar 2010' 
      ), 
     kali5 (k51, k52, k53) 
      AS (SELECT kali2.k22 AS Month_Name , 
         (kali1.k1) AS percentilevalue , 
         kali2.k21 AS percentilerow 
       FROM  kali2 
         INNER JOIN kali1 ON kali1.k4 = kali2.k22 
       WHERE kali1.k7 = kali2.k21 
      ) 
    SELECT kali3.k31 AS Median , 
      kali3.k32 AS Month_Name , 
      MAX(kali4.k41) AS Max_Mins_In_AE , 
      SUM(kali4.k41) AS Mins_IN_AE , 
      kali5.k51 AS Month_Name , 
      kali5.k52 AS percentile 
    FROM kali3 
      LEFT JOIN kali4 ON kali3.k32 = kali4.k44 
      LEFT JOIN kali5 ON kali5.k51 = kali3.k32 
    GROUP BY kali3.k31 , 
      kali3.k32 , 
      kali5.k51 , 
      kali5.k52 
0

95日百分公式是 MAX(ROWNUMBER)*100分之95

WITH kali1(k1, k2, k3, k4, k5, k6, k7) AS 
(
    SELECT MinsInAE, 
      HoursInAE, 
      DaysInAE AS DaysInAE, 
      Month_Name, 
      YearName, 
      InternalNo, 
      ROW_NUMBER() OVER(PARTITION BY Month_Name ORDER BY MinsInAE ASC) AS 
      'Row Number' 
    FROM AE.FactAandE 
      INNER JOIN AE.PMI 
       ON AE.FactAandE.FK_PaitentMasterIndex = AE.PMI.PK_Patient 
      INNER JOIN dbo.TimeDimension 
       ON dbo.TimeDimension.DateId = AE.FactAandE.FK_date 
    WHERE YearName = 'Calendar 2010' 
) 
, 
kali2(k21, k22, k23) 
AS 
(
    SELECT MAX(k7) * 95/100, 
      k4, 
      MAX(k7) 
    FROM kali1 
    GROUP BY 
      k4 
) 
SELECT kali2.k21 AS percentilerow, 
     kali2.k22 AS Month_Name, 
     (kali1.k1) AS percentilevalue 
FROM kali2 
     INNER JOIN kali1 
      ON kali1.k4 = kali2.k22 
WHERE kali1.k7 = kali2.k21 
+1

請格式化此sql代碼。 –

0

您可以創建在Visual Studio中的DLL通過創建SQL Server中使用自定義的聚合函數來做到這一點。爲此,創建一個新的Visual Studio項目,並將目標框架設置爲.NET 3.5(這適用於SQL 2008,它在SQL 2012中可能不同)。然後創建一個類文件並放入以下代碼或c#等價物。

請注意,此算法會獲得與指定百分位數最接近的值。如果你想使用不同的百分比算法,那麼可以修改代碼。

此過程允許用戶輸入任何百分點來查詢。查詢應該是這樣的:SELECT dbo.Percentile(價值95)FROM表

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 Percentile 
    Implements IBinarySerialize 
    Private _items As List(Of Decimal) 
    Private _percentile As Integer 

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

    Public Sub Accumulate(value As SqlDecimal, percentile As SqlInt32) 
    _percentile = percentile 
    If Not value.IsNull Then 
     _items.Add(value.Value) 
    End If 
    End Sub 

    Public Sub Merge(other As Percentile) 
    _percentile = other._percentile 
    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() 

     Dim index = Convert.ToInt32(Math.Round((_percentile/100D) * _items.Count, 0)) 
     If (index <> 0) Then 
     index -= 1 
     End If 
     result = _items(index) 

     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() 

    If Not (String.IsNullOrEmpty(list)) Then 
     Dim index = list.IndexOf("|"c) 

     If index <> -1 Then 
     _items = New List(Of Decimal) 
     _percentile = Convert.ToInt32(list.Substring(0, index)) 
     list = list.Substring(index + 1) 

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

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

    If (_items IsNot Nothing AndAlso _items.Count > 0) Then 
     list = Convert.ToString(_percentile) + "|" 
     For Each item In _items 
     If Not list.EndsWith("|") Then 
      list += "," 
     End If 
     list += item.ToString("#0.0##") 
     Next 
    End If 
    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 Percentile(@value decimal(9, 3), @percentile int) 
RETURNS decimal(9, 3) 
EXTERNAL NAME [CustomAggregate].[{namespace of your DLL}.Percentile]; 
GO