我可以在MySQL中使用参数创建视图吗?

sso*_*zak 85 mysql parameters stored-procedures view

我有这样的观点:

CREATE VIEW MyView AS
   SELECT Column FROM Table WHERE Value = 2;
Run Code Online (Sandbox Code Playgroud)

我想让它更通用,它意味着将2变为变量.我试过这个:

CREATE VIEW MyView AS
   SELECT Column FROM Table WHERE Value = @MyVariable;
Run Code Online (Sandbox Code Playgroud)

但MySQL不允许这样做.

我找到了一个丑陋的解决方法:

CREATE FUNCTION GetMyVariable() RETURNS INTEGER DETERMINISTIC NO SQL
BEGIN RETURN @MyVariable; END|
Run Code Online (Sandbox Code Playgroud)

然后观点是:

CREATE VIEW MyView AS
   SELECT Column FROM Table WHERE Value = GetMyVariable();
Run Code Online (Sandbox Code Playgroud)

但它看起来很糟糕,而且用法也很糟糕 - 我必须在每次使用视图之前设置@MyVariable.

有没有解决方案,我可以像这样使用:

SELECT Column FROM MyView(2) WHERE (...)
Run Code Online (Sandbox Code Playgroud)

具体情况如下:我有一个表存储有关被拒绝请求的信息:

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;
Run Code Online (Sandbox Code Playgroud)

多重性是在同一秒内记录的多个相同请求.我想显示一个拒绝列表,但有时候,当应用程序被拒绝时,它会重试几次以确保.通常情况下,当同一个用户在几秒钟内对同一个功能进行3次拒绝时,实际上是一次拒绝.如果我们还有一个资源,为了满足这个要求,接下来的两个拒绝就不会发生.因此,我们希望将报告中的拒绝分组,允许用户指定拒绝应分组的时间跨度.例如,如果我们在时间戳中拒绝(对于功能1上的用户1):1,2,24,26,27,45并且用户想要将拒绝彼此接近而不是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;
Run Code Online (Sandbox Code Playgroud)

然后,为了显示用户1和2对每5秒合并的功能3和4的拒绝,您所要做的就是:

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

我使用视图,因为在它中很容易过滤数据并在jQuery网格中显式使用它,自动排序,限制记录数等等.

但这只是一个丑陋的解决方法.有没有正确的方法来做到这一点?

小智 143

实际上如果你创建func:

create function p1() returns INTEGER DETERMINISTIC NO SQL return @p1;
Run Code Online (Sandbox Code Playgroud)

并查看:

create view h_parm as
select * from sw_hardware_big where unit_id = p1() ;
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用参数调用视图:

select s.* from (select @p1:=12 p) parm , h_parm s;
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助.

  • 哇,这是我在SQL中看到的最讨厌的东西之一;)但这正是我想要做的. (25认同)
  • 什么是'parm`? (4认同)
  • 变量p1在此之后保留其值,因此如果您再次使用视图而不传递参数,它将使用先前传递的 - 这可能会令人困惑!你可以在使用之后"清除"它:选择s.*from(select p1:= 12 p)pass,h_parm s,(select @ p1:= - 1)clear; (假设-1是用于此目的的无效值) (4认同)
  • 如果多个数据库租户同时调用此代码,是否有任何潜在问题(租户数据混淆)? (3认同)
  • @MosheElisha 如果视图是您使用此函数的唯一位置,并且您知道该函数在视图中是确定性的,那么您将通过指定“DETERMINISTIC”获得轻微的性能提升,并且这样做是完全安全的。我不相信 MySQL 会跨查询缓存函数结果。 (2认同)
  • 当创建的视图依赖于传递给存储过程的varchar时,此技术在存储过程中创建视图时有效.在这种情况下,我不得不'设置@ p1 = 12;' 在调用之前的行上创建视图. (2认同)
  • @Mr_and_Mrs_D派生表需要别名.你可以随意调用它,但你不能省略它 (2认同)

Min*_*ker 20

CREATE VIEW MyView AS
   SELECT Column, Value FROM Table;


SELECT Column FROM MyView WHERE Value = 1;
Run Code Online (Sandbox Code Playgroud)

在MySQL中是正确的解决方案,其他一些SQL可以让您更准确地定义视图.

注意:除非View非常复杂,否则MySQL会很好地优化它.

  • 在我的情况下,我想在其中使用参数的 WHERE 部分位于嵌套选择中,因此不可能从视图外部对其进行过滤。 (2认同)
  • 然后根本不使用视图,如果您需要精确控制每次构建整个查询,或者在存储过程中构建查询.保存视图似乎毫无意义.虽然如果你发布了你想要实现的查询,那么某人可能会建议一条不同/更好的路线. (2认同)

Jus*_*art 5

我之前提出了一种不同的解决方法,它不使用存储过程,而是使用参数表和一些connection_id() 魔法。

编辑(从评论中复制)

创建一个包含名为connection_id(使其成为 bigint)的列的表。在该表中放置视图参数的列。将主键放在connection_id. 替换到参数表中并用于CONNECTION_ID()填充connection_id 值。在视图中使用交叉连接到参数表并 put WHERE param_table.connection_id = CONNECTION_ID()。这将仅与参数表中的一行进行交叉连接,这就是您想要的。然后,您可以使用 where 子句中的其他列,例如 where orders.order_id = param_table.order_id