Альтернатива для процентили_конта в SQL Server 2008 - PullRequest
1 голос
/ 14 февраля 2012

В Oracle это работает хорошо ......

Запрос для Oracle - это как следует

Select distinct channel_id, position_id,datamonth, 
    percentile_cont(.9) within group (order by TRIM_PRE_ELIG_PAY) 
      over (partition by channel_id, position_id, datamonth) as TRIM_PRE_ELIG_PAY_90th_PERC 
from Tablename

Но для SQL Server я получаю сообщение об ошибке.Вот запрос для SQL Server 2008:

Select
   distinct channel_id,
   position_id, datamonth, 
   percentile_cont(.9) within group (order by TRIM_PRE_ELIG_PAY) 
     over (partition by channel_id) as TRIM_PRE_ELIG_PAY_90th_PERC 
from table

ОШИБКА: выбор не может быть проанализирован правильно.Вывод не может быть сгенерирован.

Я узнал, что он может нормально работать в SQL Server 2012, но нужен альтернативный способ в SQL Server 2008

Может кто-нибудь помочь ...........

Ответы [ 2 ]

2 голосов
/ 14 февраля 2012

В блоге SQL Server Engine есть обходной путь, который применяется к SQL Server 2005 +

К сожалению, он довольно длинный и запутанный: я оставлю вам ссылку, а не попытаюсь адаптировать ее для вашего запроса ...

1 голос
/ 23 апреля 2012

Вы можете создать функцию агрегирования CLR, чтобы реализовать то же самое. Единственным недостатком является то, что вам придется немного перестроить запрос. Я реализовал процентиль_конт с помощью CLR. Прочитайте здесь о том, как создать CLR. Затем вы можете использовать этот код, чтобы получить тот же O / P, что и Percent_cont. Это намного проще, чем писать несколько утверждений.

Вы можете определенно доработать / настроить немного в зависимости от вашего использования.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;


[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
    Format.UserDefined,
    IsInvariantToDuplicates = false,
    IsInvariantToNulls = false,
    IsInvariantToOrder = false,
    MaxByteSize = 8000)]
public struct Percentile_Cont : IBinarySerialize
{
    //Variables to hold the values;
    private List<decimal> _list;
    private decimal _percentile;

    public void Init()
    {
        _list = new List<decimal>();
        _percentile = new decimal();
    }

    public void Accumulate(SqlDecimal value,SqlDecimal percentile)
    {
        if (!value.IsNull)
        {
            _list.Add(value.Value);
            _percentile = (decimal)percentile;
        }
    }

    ///

    /// Merge the partially computed aggregate with this aggregate.
    /// 
    /// The other partial results to be merged
    public void Merge(Percentile_Cont group)
    {
        this._list.AddRange(group._list.ToArray());
    }

    ///

    /// Called at the end of aggregation, to return the results.
    /// 
    /// The percentile of all inputted values
    public SqlDecimal Terminate()
    {
        if (_list.Count == 0)
            return SqlDecimal.Null;
        _list.Sort();

        if (_percentile < 0 || _percentile >= 1)
            return SqlDecimal.Null;

        var index = 
            (int) Math.Ceiling
            (_percentile * _list.Count  + 0.5m);

        if(index > _list.Count)
        {
            index = index - 1;
        }

        return _list[index-1];

    }


    #region IBinarySerialize Members

    public void Read(System.IO.BinaryReader binaryReader)
    {
        int cnt = binaryReader.ReadInt32();
        this._list = new List<decimal>(cnt);
        this._percentile = new decimal();
        for (int i = 0; i < cnt; i++)
        {
            this._list.Add(binaryReader.ReadDecimal());
        }
        this._percentile = binaryReader.ReadDecimal();
    }

    public void Write(System.IO.BinaryWriter binaryWriter)
    {
        binaryWriter.Write(this._list.Count);
        foreach (decimal d in this._list)
        {
            binaryWriter.Write(d);
        }
        binaryWriter.Write(_percentile);
    }

    #endregion
}
...