MySQLでパラメーター付きのビューを作成できますか?


91

私はこのような見解を持っています:

CREATE VIEW MyView AS
   SELECT Column FROM Table WHERE Value = 2;

もっと一般的にしたいのですが、これは2を変数に変更することを意味します。私はこれを試しました:

CREATE VIEW MyView AS
   SELECT Column FROM Table WHERE Value = @MyVariable;

しかし、MySQLはこれを許可していません。

私は醜い回避策を見つけました:

CREATE FUNCTION GetMyVariable() RETURNS INTEGER DETERMINISTIC NO SQL
BEGIN RETURN @MyVariable; END|

そして、ビューは次のとおりです。

CREATE VIEW MyView AS
   SELECT Column FROM Table WHERE Value = GetMyVariable();

しかし、それは本当にひどく見えます、そして使用法もひどいです-私はビューの各使用法の前に@MyVariableを設定しなければなりません。

私がこのように使用できる解決策はありますか:

SELECT Column FROM MyView(2) WHERE (...)

具体的な状況は次のとおりです。拒否された要求に関する情報を格納するテーブルがあります。

CREATE TABLE Denial
(
    Id INTEGER UNSIGNED AUTO_INCREMENT,
        PRIMARY KEY(Id),
    DateTime DATETIME NOT NULL,
    FeatureId MEDIUMINT UNSIGNED NOT NULL,
        FOREIGN KEY (FeatureId)
            REFERENCES Feature (Id)
            ON UPDATE CASCADE ON DELETE RESTRICT,
    UserHostId MEDIUMINT UNSIGNED NOT NULL,
        FOREIGN KEY (UserHostId)
            REFERENCES UserHost (Id)
            ON UPDATE CASCADE ON DELETE RESTRICT,
    Multiplicity MEDIUMINT UNSIGNED NOT NULL DEFAULT 1,
    UNIQUE INDEX DenialIndex (FeatureId, DateTime, UserHostId)
) ENGINE = InnoDB;

多重度とは、同じ秒に記録される同一のリクエストの数です。拒否のリストを表示したいのですが、アプリケーションが拒否されたときに、念のため数回再試行します。そのため、通常、同じユーザーが数秒間に同じ機能を3回拒否すると、実際には1回拒否されます。この要求を満たすためにもう1つのリソースがある場合、次の2つの拒否は行われません。したがって、レポート内の拒否をグループ化して、ユーザーが拒否をグループ化する期間を指定できるようにします。たとえば、タイムスタンプに(機能1のユーザー1の)拒否があり、ユーザーが4秒よりも近い拒否をグループ化したい場合、次のような結果が得られます。 1(x2)、24(x3)、45(x1)。実際の拒否間のスペースは、重複間のスペースよりもはるかに大きいと想定できます。

CREATE FUNCTION GetDenialMergingTime()
    RETURNS INTEGER UNSIGNED
    DETERMINISTIC NO SQL
BEGIN
    IF ISNULL(@DenialMergingTime) THEN
        RETURN 0;
    ELSE
        RETURN @DenialMergingTime;
    END IF;
END|

CREATE VIEW MergedDenialsViewHelper AS
    SELECT MIN(Second.DateTime) AS GroupTime,
        First.FeatureId,
        First.UserHostId,
        SUM(Second.Multiplicity) AS MultiplicitySum
    FROM Denial AS First 
        JOIN Denial AS Second 
            ON First.FeatureId = Second.FeatureId
                AND First.UserHostId = Second.UserHostId
                AND First.DateTime >= Second.DateTime
                AND First.DateTime - Second.DateTime < GetDenialMergingTime()
    GROUP BY First.DateTime, First.FeatureId, First.UserHostId, First.Licenses;

CREATE VIEW MergedDenials AS
    SELECT GroupTime, 
        FeatureId,
        UserHostId, 
        MAX(MultiplicitySum) AS MultiplicitySum
    FROM MergedDenialsViewHelper
    GROUP BY GroupTime, FeatureId, UserHostId;

次に、5秒ごとにマージされた機能3と4でユーザー1と2からの拒否を表示するには、次のようにします。

SET @DenialMergingTime := 5;
SELECT GroupTime, FeatureId, UserHostId, MultiplicitySum FROM MergedDenials WHERE UserHostId IN (1, 2) AND FeatureId IN (3, 4);

データをフィルタリングしてjQueryグリッドで明示的に使用したり、自動的に順序付けしたり、レコード数を制限したりするのが簡単なので、ビューを使用します。

しかし、これは醜い回避策です。これを行う適切な方法はありますか?

回答:


158

実際にfuncを作成した場合:

create function p1() returns INTEGER DETERMINISTIC NO SQL return @p1;

そして見る:

create view h_parm as
select * from sw_hardware_big where unit_id = p1() ;

次に、パラメーターを指定してビューを呼び出すことができます。

select s.* from (select @p1:=12 p) parm , h_parm s;

お役に立てば幸いです。


30
うわー、これは私がSQLで見た中で最もハックなものの1つです;)しかし、それはまさに私がやりたかったことです。
ssobczak

2
この手法は、ストアドプロシージャ内にビューを作成するときに、作成されたビューがストアドプロシージャに渡されるvarcharに依存している場合に機能します。この場合、「@ p1 = 12を設定する」必要がありました。ビューを作成する呼び出しの前の行。
クレイトンスタンリー

2
複数のデータベーステナントがこのコードを同時に呼び出す場合、問題(テナントデータの混在)の可能性はありますか?
グルーバー

2
@Mr_and_Mrs_D派生テーブルにはエイリアスが必要です。あなたはそれを好きなように呼ぶことができますが、それを省略することはできません
Robin Kanters '24

4
変数p1はこの後もその値を保持するため、パラメーターを渡さずにビューを再度使用すると、渡された以前のビューが使用されます-これは混乱を招く可能性があります!次のように使用した後は、「クリア」できます。selects。* from(select p1:= 12 p)pass、h_parm s、(select @ p1:=-1)clear; (この目的のために-1が無効な値であると想定)
BuvinJ

21
CREATE VIEW MyView AS
   SELECT Column, Value FROM Table;


SELECT Column FROM MyView WHERE Value = 1;

MySQLでは適切なソリューションですが、他のいくつかのSQLではビューをより正確に定義できます。

注:ビューが非常に複雑でない限り、MySQLはこれを適切に最適化します。


1
私の場合、パラメーターを使用したいWHERE部分は、neasted selectにあるため、ビューの外側からフィルターすることはできません。
ssobczak 2010

実際にはneasted selectはビューでは許可されていませんが、2つのビューに分割しました。V1はデータをフィルタリングして集計し、V1の上にV2があります。V1の外側(V2内)のデータはフィルターできません。外側のデータは集約されているように見えるためです。
ssobczak 2010

2
次に、ビューをまったく使用しないでください。正確な制御が必要な場合は、毎回クエリ全体を作成するか、ストアドプロシージャ内でクエリを作成してください。ビューとして保存しても意味がありません。ただし、クエリを投稿すると、他の人が別の/より良いルートを提案できる可能性があります。
MindStalker 2010

私はこれをしたくなかったので、単純な質問はかなり複雑になるので、もしあなたがそれが役に立つかもしれないと思ったら、私はやってみます。
ssobczak 2010

1

私は以前、ストアドプロシージャを使用せず、代わりにパラメーターテーブルといくつかのconnection_id()マジックを使用する別の回避策を考え出しました。

編集(コメントからコピー)

という列を含むテーブルを作成しますconnection_id(bigintにします)。ビューのパラメーター用にそのテーブルに列を配置します。に主キーを置きconnection_idます。パラメータテーブルに置き換えて、CONNECTION_ID()connection_id値の入力に使用します。ビュー使用時にはクロスは、パラメータテーブルとプットに参加しますWHERE param_table.connection_id = CONNECTION_ID()。これは、必要なパラメータテーブルの1行のみと交差結合します。その後、where句などの他の列を使用できますorders.order_id = param_table.order_id


5
どれ?もう少し教えてください。
marzapower 2011

1
connection_idという列を含むテーブルを作成します(bigintにします)。ビューのパラメーター用にそのテーブルに列を配置します。connection_idに主キーを配置します。パラメータテーブルに置き換え、CONNECTION_ID()を使用してconnection_id値を入力します。ビューで、パラメーターテーブルへのクロス結合を使用し、WHERE param_table.connection_id = CONNECTION_ID()を配置します。これは、必要なパラメータテーブルの1行のみと交差結合します。次に、where句の他の列を使用できます(たとえば、whereorders.order_id = param_table.order_id)。
ジャスティンスワンハート2013年

クラッジ!でもかわいい。
リックジェームズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.