web-dev-qa-db-ja.com

MySQLのパラメーターを使用してビューを作成できますか?

私はこのようなビューを持っています:

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

2を変数に変更することを意味します。私はこれを試しました:

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

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

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

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秒よりも互いに近い拒否をグループ化する場合、次のようになります。 (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グリッドで明示的に使用し、自動的に順序付けし、レコードの数を制限するなどが簡単だからです。

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

82
ssobczak

実際に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;

役に立てば幸いです。

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


SELECT Column FROM MyView WHERE Value = 1;

MySQLの適切なソリューションです。他のSQLを使用すると、ビューをより正確に定義できます。

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

19
MindStalker

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

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

_connection_id_という列を含むテーブルを作成します(bigintにします)。ビューのパラメーターの列をそのテーブルに配置します。 _connection_id_に主キーを配置します。パラメータテーブルに置き換え、CONNECTION_ID()を使用してconnection_id値を設定します。ビューで、パラメーターテーブルへのクロス結合を使用し、WHERE param_table.connection_id = CONNECTION_ID()を配置します。これにより、パラメータテーブルの1つの行のみを使用したクロス結合が可能になります。その後、where句の他の列を使用できます(たとえば、where _orders.order_id = param_table.order_id_)。

1
Justin Swanhart