Pregunta ¿Puedo crear vistas con parámetros en MySQL?


Tengo una vista como esta:

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

Me gustaría hacerlo más genérico, significa cambiar 2 en una variable. Intenté esto:

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

Pero mysql no permite esto.

Encontré una solución fea:

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

Y luego ver es:

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

Pero se ve muy mal, y el uso también es malo: tengo que configurar @MyVariable antes de cada uso de la vista.

¿Hay alguna solución que pueda usar así?

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

La situación concreta es la siguiente: Tengo una tabla que almacena información sobre la solicitud denegada:

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;

La multiplicidad es el número de solicitudes idénticas registradas en el mismo segundo. Quiero mostrar una lista de denegaciones, pero a veces, cuando se deniega la aplicación, se reintenta un par de veces para asegurarse. Por lo general, cuando el mismo usuario obtiene la negación 3 veces en la misma función en un par de segundos, en realidad es una denegación. Si tuviéramos un recurso más, para cumplir con esta solicitud, las próximas dos denegaciones no sucederían. Por lo tanto, queremos agrupar las denegaciones en el informe, lo que permite al usuario especificar el intervalo de tiempo en el que se deben agrupar las denegaciones. P.ej. si tenemos denegaciones (para el usuario 1 en la función 1) en las indicaciones de fecha y hora: 1,2,24,26,27,45 y el usuario desea agrupar las denegaciones que están más cercanas entre sí que 4 segundos, debería obtener algo como esto: 1 (x2), 24 (x3), 45 (x1). Podemos suponer que los espacios entre las negaciones reales son mucho mayores que entre las duplicaciones. Resolví el problema de la siguiente manera:

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;

Luego, para mostrar las negativas del usuario 1 y 2 en las funciones 3 y 4 fusionadas cada 5 segundos, todo lo que tiene que hacer es:

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

Uso view, porque en él es fácil filtrar los datos y usarlos explícitamente en jQuery grid, ordenar automáticamente, limitar el número de registros, etc.

Pero es solo una solución fea. ¿Hay una forma adecuada de hacer esto?


76
2018-02-17 15:25


origen


Respuestas:


En realidad, si creas func:

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

y vista:

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

Luego puede llamar a una vista con un parámetro:

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

Espero que ayude.


121
2018-03-16 21:09



CREATE VIEW MyView AS
   SELECT Column, Value FROM Table;


SELECT Column FROM MyView WHERE Value = 1;

Es la solución adecuada en MySQL, algunos otros SQL le permiten definir las vistas más exactamente.

Nota: A menos que la Vista sea muy complicada, MySQL optimizará esto muy bien.


18
2018-02-17 15:47



Anteriormente se me ocurrió una solución alternativa que no utiliza procedimientos almacenados, sino que utiliza una tabla de parámetros y algunos magic de connection_id ().

EDITAR (copiado de los comentarios)

crear una tabla que contiene una columna llamada connection_id (hazlo un bigint). Coloque columnas en esa tabla para los parámetros de la vista. Pon una clave principal en el connection_id. reemplazar en la tabla de parámetros y usar CONNECTION_ID() para llenar el valor connection_id. En la vista use una combinación cruzada a la tabla de parámetros y ponga WHERE param_table.connection_id = CONNECTION_ID(). Esto se combinará con una sola fila de la tabla de parámetros que es lo que desea. Puede usar las otras columnas en la cláusula where donde, por ejemplo, orders.order_id = param_table.order_id.


1
2018-04-06 17:20