Могу ли я создать представление с параметром в MySQL? - PullRequest
82 голосов
/ 17 февраля 2010

У меня есть такой вид:

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

Я бы хотел сделать его более общим, это означает, что 2 нужно изменить на переменную. Я попробовал это:

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

Но MySQL не позволяет этого.

Я нашел уродливый обходной путь:

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;

Множественность - это число идентичных запросов, записанных за одну секунду. Я хочу отобразить список отказов, но иногда, когда приложение отклоняется, оно пытается повторить пару раз, чтобы убедиться. Так что обычно, когда один и тот же пользователь получает отказ три раза за одну и ту же функцию за пару секунд, это фактически одно отклонение. Если бы у нас был еще один ресурс для выполнения этого запроса, следующих двух отказов не было бы. Таким образом, мы хотим сгруппировать отказы в отчете, позволяя пользователю указать временной интервал, в который должны быть сгруппированы отказы. Например. если у нас есть отказы (для пользователя 1 в функции 1) в метках времени: 1,2,24,26,27,45 и пользователь хочет сгруппировать отказы, которые ближе друг к другу, чем 4 секунды, он должен получить что-то вроде этого: 1 (х2), 24 (х3), 45 (х1). Можно предположить, что промежутки между реальными отрицаниями намного больше, чем между дупликациями. Я решил проблему следующим образом:

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;

Затем для отображения отказов пользователей 1 и 2 в функциях 3 и 4, которые объединяются каждые 5 секунд, все, что вам нужно сделать, это:

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

Я использую представление, потому что в нем легко фильтровать данные и использовать их явно в сетке jQuery, автоматически упорядочивать, ограничивать количество записей и так далее.

Но это просто уродливый обходной путь. Есть ли правильный способ сделать это?

Ответы [ 3 ]

132 голосов
/ 17 марта 2011

На самом деле, если вы создаете 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;

Iнадеюсь, это поможет.

19 голосов
/ 17 февраля 2010
CREATE VIEW MyView AS
   SELECT Column, Value FROM Table;


SELECT Column FROM MyView WHERE Value = 1;

Является правильным решением в MySQL, некоторые другие SQL позволяют более точно определять представления.

Примечание. Если представление не очень сложное, MySQL прекрасно его оптимизирует.

1 голос
/ 06 апреля 2011

Ранее я предложил другой обходной путь, который не использует хранимые процедуры, а вместо этого использует таблицу параметров и некоторую магию connection_id ().

РЕДАКТИРОВАТЬ (скопировано из комментариев)

создайте таблицу, содержащую столбец с именем connection_id (сделайте его крупным). Поместите столбцы в эту таблицу для параметров для представления. Поместите первичный ключ на connection_id. заменить в таблицу параметров и использовать CONNECTION_ID() для заполнения значения connection_id. В представлении используйте перекрестное соединение с таблицей параметров и введите WHERE param_table.connection_id = CONNECTION_ID(). Это будет перекрестное соединение только с одной строкой из таблицы параметров, которая вам нужна. Затем вы можете использовать другие столбцы в предложении where, например, где orders.order_id = param_table.order_id.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...