7

私はいくつかのプログラムを作成しRており、クライアントに配信するために T-SQL に変換する必要があります。私は T-SQL を初めて使用し、すべてのR関数を翻訳する際にいくつかの問題に直面しています。

例として数値導関数関数があります。この関数は、2 つの入力列 (値と時間) に対して、計算された導関数を含む (同じ長さの) 別の列を返します。

私の現在の理解は次のとおりです。

  1. select次のように、この関数をステートメントと インラインで使用する必要があるため、SP は使用できません 。SELECT Customer_ID, Date, Amount, derivative(Amount, Date) FROM Customer_Detail

  2. 入力パラメーターとしてスカラーのみを使用できるため、UDF は使用できません。速度のためにベクトル化された関数が必要になります。また、上記のような一部の関数では、行ごとに実行しても意味がないためです (値ごとに次と前が必要です)

  3. UDA は列全体を取得しますが、その名前が示すように、列を集約しsumますavg

上記が正しい場合、必要なタイプの関数を作成できる他の手法はどれですか? SQL私が求めているのと同様の組み込み関数の例はsquare()、(明らかに) 列を取り、それ自体を ^2 返すものです。square私の目標は、 、 などのように動作する関数のライブラリを作成することです。ただし、内部的には、各スカラーが行から読み取られる原因と戻り値powerが異なります。User Defied に蓄積メソッド (UDA など) を使用して、インポートの最後にすべてのデータを操作し、同じ長さの列を返すことができるsquareかどうかを知りたいですか?

注意: 現在、私は SQL-Server 2005 を使用していますが、すぐに 2012 (またはおそらく数か月後に 2014) に切り替える予定なので、SQL-Server の 2005 以降のバージョンに基づく回答は問題ありません。

編集:Rうまくいけば、すでにそのような困難に直面しているR開発者向けのタグを追加しました。

EDIT2: 追加されたCLRタグ: CLRPro t-sql 2005 プログラマー ガイドで定義されているように、ユーザー定義の集計を調べました。このタイプの機能は私のニーズに合わないと既に述べましたが、検討する価値はありました。UDA に必要な 4 つのメソッドはInit、 、AccumulateMergeおよびTerminateです。私の要求では、UDA. したがってmerge、マルチコア処理からの部分的な結果をグループ化する方法を含むオプションは機能しません。

4

6 に答える 6

4

少し気分を変えてみてもいいと思います。SQL 言語は、データのセット、特に最新の RDBMS 実装 (SQL Server 2012 など) を操作する場合に非常に優れていますが、行や列ではなく、セットで考える必要があります。あなたの正確なタスクはまだわかりませんが、見てみましょう - SQL Server 2012 には非常に優れたウィンドウ関数+ランキング関数+分析関数+一般的なテーブル式があるため、ほとんどすべてのクエリをインラインで記述できます。共通テーブル式のチェーンを使用して、データを任意の方法で変換したり、累計を計算したり、ウィンドウ全体で平均やその他の集計を計算したりできます。

実際、私はずっと SQL が好きで、関数型言語 (ML と Scala) を少し学んだとき、SQL への私のアプローチは関数型言語のパラダイムに非常に似ていると思いました。 、必要な結果セットが得られるまで。

簡単な例です。ここに SO からの質問があります -グループ内の「中間」値の平均を取得する方法は? . 目標は、中間の 3 つの値の各グループの平均を取得することでした。

TEST_ID TEST_VALUE  GROUP_ID
1       5           1       -+
2       10          1        +- these values for group_id = 1
3       15          1       -+
4       25          2       -+
5       35          2        +- these values for group_id = 2
6       5           2       -+
7       15          2       
8       25          3
9       45          3       -+
10      55          3        +- these values for group_id = 3
11      15          3       -+
12      5           3
13      25          3
14      45          4       +- this value for group_id = 4

私にとって、R で行うのは簡単な作業ではありませんが、SQL では、次のような非常に単純なクエリになる可能性があります。

with cte as (
    select
        *,
        row_number() over(partition by group_id order by test_value) as rn,
        count(*) over(partition by group_id) as cnt
    from test
)
select
    group_id, avg(test_value)
from cte
where
    cnt <= 3 or
    (rn >= cnt / 2 - 1 and rn <= cnt / 2 + 1)
group by group_id

このクエリを簡単に拡張して、中央あたりの 5 つの値を取得することもできます。

分析関数を詳しく見て、ウィンドウ関数の観点から計算を再考してみてください。R プロシージャをプレーン SQL で書き直すのはそれほど難しくないかもしれません。

それが役に立てば幸い。

于 2013-09-30T19:28:23.903 に答える
3

これは、カーソルを使用しない純粋な T-SQL では不可能だと思います。しかし、カーソルを使用すると、通常は非常に遅くなります。カーソルはテーブルを行ごとに処理しており、これを「スローバイスロー」と呼ぶ人もいます。

ただし、独自の集計関数を作成できます (詳細については、 Technetを参照してください)。.NET CLR (C# やR.NET など) を使用して関数を実装する必要があります。

良い例については、こちらを参照してください。

R と SQL のインターフェースは非常に優れたソリューションだと思います。Oracle はこの組み合わせを商用製品として提供しているので、SQL Server と同じ方法を試してみませんか。

独自の集計関数を使用してコードに R を統合する場合、わずかなパフォーマンス ペナルティしか発生しません。Microsoft のドキュメントによると、独自の集計関数は非常に高速です。また、R.NET ソリューションは、ネイティブ R DLL を実行中のプロセスに直接ロードすることで、非常に高速に見えるようです。そのため、R over ODBC を使用するよりもはるかに高速になるはずです。

于 2013-10-01T12:44:27.890 に答える
3

処理するレコードへの参照を渡すことでこれを解決し、いわゆる「インライン テーブル値関数」を使用して、最初のレコードを処理した後にレコードを返します。

テーブル関数のリファレンスは、 http ://technet.microsoft.com/en-en/library/ms186755.aspx にあります。

サンプル:

    CREATE FUNCTION Sales.CustomerExtendedInfo (@CustomerID int)
RETURNS TABLE
AS
RETURN 
(
    SELECT FirstName + LastName AS CompleteName, 
           DATEDIFF(Day,CreateDate,GetDate()) AS DaysSinceCreation
    FROM Customer_Detail
    WHERE CustomerID = @CustomerID

);
GO

StoreID は、処理するレコードの主キーになります。

一度に複数のレコードを処理する場合は、Table-Function を後で他のクエリ結果に結合できます。

ここにサンプルがあります:

SELECT  * FROM Customer_Detail
CROSS APPLY Sales.CustomerExtendedInfo (CustomerID) 

通常のストアド プロシージャを使用しても多かれ少なかれ同じことができますが、結果をプログラムで操作するのは少し難しいです。

ただし、1 つ注意してください。SQL-Server は「関数型プログラミング」には適していません。データやデータのセットを操作するのは素晴らしいことですが、「アプリケーション サーバー」として使用すればするほど、そのために作られていないことに気付くでしょう。

于 2013-09-26T16:36:53.587 に答える
2

元の応答:

必要な関数がすでにわかっている場合、私が考えることができるアプローチの 1 つは、テーブルごとに適用するメソッド/操作ごとに 1 つのインライン関数を作成することです。それはどういう意味ですか?たとえば、1 つのメソッド「derivative(Amount, Date)」が必要な場合があることを選択したときに、FROM Customer_Detail テーブルについて言及しました。あなたが必要とするかもしれない2番目の方法(私は説明を補うだけです)が「derivative1(Amount1、Date1)」であるとしましょう。2 つのインライン関数を作成します。それぞれが目的の列の関数内で独自の計算を行い、残りの列もそのまま返します。そうすれば、テーブルから取得したときにすべての列を取得し、スカラー操作ではなくセットベースの操作としてカスタム計算を実行します。後で、意味があれば、同じ関数で列の独立した計算を組み合わせることができます。このすべての関数を引き続き使用し、必要に応じて JOIN を実行して、すべてのカスタム計算を単一のセットで取得できます。これは、すべての関数が共通/未処理の列をそのまま使用するためです。以下の例を参照してください。

    IF object_id('Product','u') IS NOT NULL
          DROP TABLE Product
    GO
    CREATE TABLE Product
    (
          pname       sysname NOT NULL
          ,pid        INT         NOT NULL
          ,totalqty   INT         NOT NULL DEFAULT 1
          ,uprice           NUMERIC(28,10)    NOT NULL DEFAULT 0
    )
    GO
    INSERT INTO Product( pname, pid, totalqty, uprice )
                      SELECT      'pen',1,100,1.2
    UNION ALL   SELECT      'book',2,300,10.00
    UNION ALL   SELECT      'lock',3,500,15.00
    GO

    IF object_id('ufn_Product_totalValue','IF') IS NOT NULL
          DROP FUNCTION ufn_Product_totalValue
    GO
    CREATE FUNCTION ufn_Product_totalValue
    (
          @newqty           int
          ,@newuprice numeric(28,10)
    )
    RETURNS TABLE AS
    RETURN
    (
          SELECT pname,pid,totalqty,uprice,totalqty*uprice AS totalValue
          FROM
          (
                SELECT 
                            pname
                            ,pid
                            ,totalqty+@newqty AS totalqty
                            ,uprice+@newuprice AS uprice
                FROM Product
          )qry
    )
    GO

    IF object_id('ufn_Product_totalValuePct','IF') IS NOT NULL
          DROP FUNCTION ufn_Product_totalValuePct
    GO
    CREATE FUNCTION ufn_Product_totalValuePct
    (
          @newqty           int
          ,@newuprice numeric(28,10)
    )
    RETURNS TABLE AS
    RETURN
    (
          SELECT pname,pid,totalqty,uprice,totalqty*uprice/100 AS totalValuePct
          FROM
          (
                SELECT 
                            pname
                            ,pid
                            ,totalqty+@newqty AS totalqty
                            ,uprice+@newuprice AS uprice
                FROM Product
          )qry
    )
    GO

    SELECT * FROM ufn_Product_totalValue(10,5)

    SELECT * FROM ufn_Product_totalValuepct(10,5)

    select tv.pname,tv.pid,tv.totalValue,pct.totalValuePct
    from ufn_Product_totalValue(10,5) tv
    join ufn_Product_totalValuePct(10,5) pct
        on tv.pid=pct.pid

以下に示すように、出力も確認してください。 ここに画像の説明を入力

EDIT2:

3 点平滑化アルゴリズム

ここに画像の説明を入力

    IF OBJECT_ID('Test3PointSmoothingAlgo','u') IS NOT NULL
        DROP TABLE Test3PointSmoothingAlgo
    GO
    CREATE TABLE Test3PointSmoothingAlgo
    (
        qty INT NOT NULL
        ,id INT IDENTITY NOT NULL
    )
    GO
    INSERT Test3PointSmoothingAlgo( qty ) SELECT 10 UNION SELECT 20 UNION SELECT 30
    GO

    IF object_id('ufn_Test3PointSmoothingAlgo_qty','IF') IS NOT NULL
          DROP FUNCTION ufn_Test3PointSmoothingAlgo_qty
    GO
    CREATE FUNCTION ufn_Test3PointSmoothingAlgo_qty
    (
        @ID INT --this is a dummy parameter
    )
    RETURNS TABLE AS
    RETURN
    (
        WITH CTE_3PSA(SmoothingPoint,Coefficients)
        AS --finding the ID of adjacent points
        (
            SELECT id,id
            FROM Test3PointSmoothingAlgo
            UNION
            SELECT id,id-1
            FROM Test3PointSmoothingAlgo
            UNION
            SELECT id,id+1
            FROM Test3PointSmoothingAlgo 
        )
        --Apply 3 point Smoothing algorithms formula
        SELECT a.SmoothingPoint,SUM(ISNULL(b.qty,0))/3 AS Qty_Smoothed--this is a using 3 point smoothing algoritham formula
        FROM CTE_3PSA a
        LEFT JOIN Test3PointSmoothingAlgo b
        ON a.Coefficients=b.id
        GROUP BY a.SmoothingPoint
    )
    GO

    SELECT SmoothingPoint,Qty_Smoothed FROM dbo.ufn_Test3PointSmoothingAlgo_qty(NULL)

ここに画像の説明を入力

于 2013-10-03T04:21:32.323 に答える
1

機能を2つの部分に分割する必要があるかもしれないと思います-OVER (...)結果のスカラーを結合する句と式のおかげでスコープで機能するUDAに。

あなたが求めていること-集約/スカラーコンボにするような方法でオブジェクトを定義すること-は、CLRコードにフォールバックしない限り、おそらく通常のSQL Serverの機能の範囲外であり、実質的にカーソルと同等になりますパフォーマンスまたはそれより悪い。

あなたの最善の策は、全体の結果を生み出すSPをおそらく定義することです(私はあなたがそれを知らないことを知っています)。同様に、テーブル名と列名をパラメーターとしてパラメーターを受け取る [派生] ストアド プロシージャを作成します。アイデアを拡張することもできますが、最終的には、それはまさにあなたが望むものではありません。

于 2013-10-04T12:33:39.687 に答える