sql >> データベース >  >> RDS >> Oracle

リレーショナルデータベースでストアドプロシージャからの選択がサポートされていないのはなぜですか?

    TL; DR できる (テーブル値の)関数から、またはPostgreSQLの任意の種類の関数から選択します。ただし、ストアドプロシージャからではありません。

    これは「直感的」で、データベースに依存しない説明です。SQLとその多くの方言は、有機的に成長した言語/概念ではありすぎて、基本的な「科学的」な説明ができないと思います。

    手順と機能、歴史的に

    ストアドプロシージャから選択する意味はよくわかりませんが、長年の経験と現状を受け入れることに偏りがあり、プロシージャの違いがどのようになっているのかは確かにわかります。 および関数 混乱する可能性があり、どのようにそれらがより用途が広く強力であることを望むか。特にSQLServer、Sybase、またはMySQLでは、プロシージャは任意の数の結果セット/更新カウントを返すことができますが、これは明確に定義された型を返す関数と同じではありません。

    手順を命令型ルーチンと考えてください (副作用あり)および純粋なルーチンとしての機能 副作用なし。 SELECT ステートメント自体も「純粋」です。 (潜在的なロック効果は別として)副作用がないため、関数をSELECTで使用できる唯一のタイプのルーチンと考えるのは理にかなっています。 ステートメント。

    実際、関数は動作に強い制約があるルーチンであると考えてください。一方、プロシージャは任意のプログラムを実行できます。

    4GLと3GL言語

    これを見る別の方法は、SQLが第4世代プログラミング言語(4GL)であるという観点からです。 。 4GLは、実行できることが大幅に制限されている場合にのみ、合理的に機能します。 一般的なテーブル式によりSQLチューリング完全化> 、はい、しかしSQLの宣言型の性質は、実用的な日常の観点から、SQLが汎用言語であることを依然として妨げています。

    ストアドプロシージャは、この制限を回避する方法です。時々、あなたはしたい チューリング完全および 実用的。したがって、ストアドプロシージャは、命令型、副作用、トランザクション型などに頼っています。

    保存された関数は、いくつかを導入するための賢い方法です。 3GL /手続き型言語の機能は、内部の副作用を禁止するという代償を払って、より純粋な4GLの世界に組み込まれます(パンドラの箱を開けて、完全に予測できないSELECTが必要な場合を除きます)。 ステートメント)。

    一部のデータベースでは、ストアドプロシージャが任意の数の結果セット/カーソルを返すことができるという事実は、副作用を含む任意の動作を許可するという特徴です。原則として、保存された関数でもこの特定の動作を妨げるものは何もありませんが、4GL言語であるSQLのコンテキスト内でそうすることが許可されている場合、管理は非常に非現実的で困難です。

    したがって:

    • プロシージャは、プロシージャ、任意の関数、およびSQLを呼び出すことができます
    • 「純粋」関数は「純粋」関数とSQLを呼び出すことができます
    • SQLは「純粋」関数とSQLを呼び出すことができます

    しかし:

    • プロシージャを呼び出す「純粋」関数は(プロシージャのような)「純粋」関数になります

    そして:

    • SQLはプロシージャを呼び出すことができません
    • SQLは「不純な」関数を呼び出すことはできません

    「純粋な」テーブル値関数の例:

    表値の「純粋」関数の使用例を次に示します。

    Oracle

    CREATE TYPE numbers AS TABLE OF number(10);
    /
    
    CREATE OR REPLACE FUNCTION my_function (a number, b number)
    RETURN numbers
    IS
    BEGIN
        return numbers(a, b);
    END my_function;
    /
    

    そして:

    SELECT * FROM TABLE (my_function(1, 2))
    

    SQL Server

    CREATE FUNCTION my_function(@v1 INTEGER, @v2 INTEGER)
    RETURNS @out_table TABLE (
        column_value INTEGER
    )
    AS
    BEGIN
        INSERT @out_table
        VALUES (@v1), (@v2)
        RETURN
    END
    

    そして

    SELECT * FROM my_function(1, 2)
    

    PostgreSQL

    PostgreSQLについて一言お願いします。

    PostgreSQLは素晴らしいので、例外です。また、奇妙なことであり、おそらくその機能の50%を本番環境で使用するべきではありません。 「プロシージャ」ではなく「関数」のみをサポートしますが、これらの関数は何でも機能します。以下を確認してください:

    CREATE OR REPLACE FUNCTION wow ()
    RETURNS SETOF INT
    AS $$
    BEGIN
        CREATE TABLE boom (i INT);
    
        RETURN QUERY
        INSERT INTO boom VALUES (1)
        RETURNING *;
    END;
    $$ LANGUAGE plpgsql;
    

    副作用:

    • テーブルが作成されます
    • レコードが挿入されます

    まだ:

    SELECT * FROM wow();
    

    収量

    wow
    ---
    1
    


    1. mysqlトリガーストアードトリガーは、ストアードトリガーを呼び出したステートメントによってすでに使用されています

    2. このクエリはSQLインジェクションから安全ですか?

    3. Pythonpsycopg2がpostgresqlテーブルに挿入されていません

    4. 開始リンクがOracle11gサーバーで機能しない