J'ai une vue comme celle-ci:
CREATE VIEW MyView AS
SELECT Column FROM Table WHERE Value = 2;
J'aimerais le rendre plus générique, cela signifie changer 2 en variable. J'ai essayé ceci:
CREATE VIEW MyView AS
SELECT Column FROM Table WHERE Value = @MyVariable;
Mais MySQL ne le permet pas.
J'ai trouvé une solution de contournement laide:
CREATE FUNCTION GetMyVariable() RETURNS INTEGER DETERMINISTIC NO SQL
BEGIN RETURN @MyVariable; END|
Et puis la vue est:
CREATE VIEW MyView AS
SELECT Column FROM Table WHERE Value = GetMyVariable();
Mais cela a l'air vraiment merdique, et l'utilisation est également merdique - je dois définir @MyVariable avant chaque utilisation de la vue.
Y a-t-il une solution que je pourrais utiliser comme celle-ci:
SELECT Column FROM MyView(2) WHERE (...)
La situation concrète est la suivante: j'ai une table contenant des informations sur la demande refusée:
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;
Une multiplicité est un nombre de requêtes identiques enregistrées dans la même seconde. Je veux afficher une liste de refus, mais parfois, lorsque l'application est refusée, elle réessaye plusieurs fois pour m'en assurer. Donc, généralement, lorsque le même utilisateur obtient un refus 3 fois sur la même fonctionnalité en quelques secondes, il s'agit en fait d'un refus. Si nous avions une ressource de plus, pour répondre à cette demande, les deux prochains refus ne se produiraient pas. Nous souhaitons donc regrouper les refus dans le rapport permettant à l'utilisateur de spécifier la période dans laquelle les refus doivent être regroupés. Par exemple, si nous avons des refus (pour l'utilisateur 1 sur la fonctionnalité 1) dans les horodatages: 1, 2, 24, 26, 27, 45 et que l'utilisateur souhaite regrouper les refus qui sont plus proches les uns des autres que 4 secondes, il devrait obtenir quelque chose comme ceci: 1 (x2), 24 (x3), 45 (x1). Nous pouvons supposer que les espaces entre les dénégations réelles sont beaucoup plus grands qu'entre les duplications.
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;
Ensuite, pour afficher les refus des utilisateurs 1 et 2 sur les fonctionnalités 3 et 4 fusionnées toutes les 5 secondes, tout ce que vous avez à faire est:
SET @DenialMergingTime := 5;
SELECT GroupTime, FeatureId, UserHostId, MultiplicitySum FROM MergedDenials WHERE UserHostId IN (1, 2) AND FeatureId IN (3, 4);
J'utilise la vue car il est facile de filtrer les données et de l'utiliser explicitement dans la grille jQuery, de les commander automatiquement, de limiter le nombre d'enregistrements, etc.
Mais c'est juste une vilaine solution de contournement. Existe-t-il une bonne façon de procéder?
la source
Est la bonne solution dans MySQL, certains autres SQL vous permettent de définir des vues plus précisément.
Remarque: à moins que la vue ne soit très compliquée, MySQL optimisera cela très bien.
la source
J'ai précédemment proposé une solution de contournement différente qui n'utilise pas de procédures stockées, mais utilise à la place une table de paramètres et un peu de magie connection_id ().
EDIT (copié à partir des commentaires)
créer une table qui contient une colonne appelée
connection_id
(en faire un bigint). Placez des colonnes dans cette table pour les paramètres de la vue. Mettez une clé primaire sur leconnection_id
. replacez dans la table des paramètres et utilisezCONNECTION_ID()
pour renseigner la valeur connection_id. Dans la vue, utilisez une jointure croisée avec la table de paramètres et mettezWHERE param_table.connection_id = CONNECTION_ID()
. Cela va créer une jointure croisée avec une seule ligne de la table de paramètres, ce que vous voulez. Vous pouvez ensuite utiliser les autres colonnes de la clause where, par exemple whereorders.order_id = param_table.order_id
.la source