2010-02-17 9 views
71

que tienen una vista como esta:¿Puedo crear vistas con el parámetro en MySQL?

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

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

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

Pero mysql no permite esto.

me encontré con un feo solución:

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

Y entonces vista es:

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

Pero parece realmente horrible, y el uso también es horrible - Tengo que fijar la @MyVariable antes cada uso de la vista.

¿Hay una solución, que podría utilizar la siguiente manera:

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

La situación concreta es la siguiente: Tengo una tabla que almacena información acerca de 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; 

multiplicidad es 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. He resuelto el problema en la siguiente forma:

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; 

continuación para mostrar las negativas de usuario 1 y 2 en funciones 3 y 4 refundidos 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); 

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

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

Respuesta

115

En realidad, si se crea func:

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

y ver:

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

A continuación, puede llamar a la vista con un parámetro:

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

espero que ayude.

+21

Wow, esta es una de las cosas más hacky que he visto en SQL;) Pero es exactamente lo que quería hacer. – ssobczak

+0

¿No debería ser NO DETERMINISTA? – MosheElisha

+0

@MichaelMior Los documentos de MySQL dicen: "Una rutina se considera" determinista "si siempre produce el mismo resultado para los mismos parámetros de entrada, y" no determinista ". Si no se proporciona DETERMINISTIC ni NOT DETERMINISTIC en la definición de rutina, el el valor predeterminado NO ES DETERMINISTA. Para declarar que una función es determinista, debe especificar DETERMINISTIC explícitamente ". - según tengo entendido, no es solo durante la ejecución de la vista. – MosheElisha

18
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.

+0

En mi caso, la parte WHERE, en la que quiero usar el parámetro, está en selección seleccionada, por lo que es imposible filtrarla desde fuera de la vista. – ssobczak

+0

Las selecciones realmente obtenidas no están permitidas en las vistas, pero las dividí en dos. V1 filtra y agrega datos, y en la parte superior de V1 hay V2. No puedo filtrar datos de V1 fuera de él (en V2), ya que fuera de ellos son visibles como agregados. – ssobczak

+1

Luego, no use una vista en absoluto, si necesita control exacto construya toda la consulta todo el tiempo, o cree la consulta dentro de un procedimiento almacenado. Guardar como una vista parece inútil. Sin embargo, si publica las consultas que está tratando de lograr, alguien podría sugerir una ruta diferente/mejor. – MindStalker

1

Me surgió anteriormente una solución diferente que no utiliza procedimientos almacenados, sino que utiliza una tabla de parámetros y algunos magic connection_id().

EDITAR (copiado a partir de los comentarios)

crear una tabla que contiene una columna llamada connection_id (lo convierten en un BIGINT). Coloque columnas en esa tabla para los parámetros de la vista. Ponga una clave principal en el connection_id. reemplace en la tabla de parámetros y use CONNECTION_ID() para llenar el valor connection_id. En la vista use una unió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. A continuación, puede usar las otras columnas en la cláusula where, por ejemplo, orders.order_id = param_table.order_id.

+5

¿Cuál? Por favor, cuéntanos algo más. – marzapower

+1

crea una tabla que contiene una columna llamada connection_id (hazla un bigint). Coloque columnas en esa tabla para los parámetros de la vista. Coloque una clave principal en el connection_id. reemplace en la tabla de parámetros y use CONNECTION_ID() para completar el valor de connection_id. En la vista, use una combinación cruzada con la tabla de parámetros y coloque 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. A continuación, puede usar las otras columnas en la cláusula where, por ejemplo, donde orders.order_id = param_table.order_id. –

+0

KLUDGE! Pero mono. –

Cuestiones relacionadas