MySQL에서 매개 변수로 뷰를 생성 할 수 있습니까?


93

다음과 같은 견해가 있습니다.

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;

다중성은 동일한 초에 기록 된 동일한 요청의 수입니다. 거부 목록을 표시하고 싶지만 때때로 응용 프로그램이 거부되면 확인하기 위해 몇 번 재 시도합니다. 따라서 일반적으로 동일한 사용자가 동일한 기능에 대해 몇 초 안에 3 번 거부를 받으면 실제로는 한 번의 거부입니다. 이 요청을 수행하기 위해 리소스가 하나 더 있으면 다음 두 번의 거부가 발생하지 않습니다. 따라서 사용자가 거부를 그룹화해야하는 기간을 지정할 수 있도록 보고서에서 거부를 그룹화하려고합니다. 예를 들어 타임 스탬프 : 1,2,24,26,27,45에 거부 (기능 1의 사용자 1에 대해)가 있고 사용자가 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;

그런 다음 5 초마다 병합 된 기능 3 및 4에 대한 사용자 1 및 2의 거부를 표시하려면 다음을 수행하십시오.

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

데이터를 필터링하고 jQuery 그리드에서 명시 적으로 사용하고, 자동으로 정렬하고, 레코드 수를 제한하는 등의 작업이 쉽기 때문에 뷰를 사용합니다.

그러나 그것은 추악한 해결 방법입니다. 이를 수행하는 적절한 방법이 있습니까?

답변:


161

실제로 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;

도움이되기를 바랍니다.


31
와우, 이것은 내가 SQL에서 본 것 중 가장 엉뚱한 것 중 하나입니다;)하지만 정확히 제가하고 싶었던 것입니다.
ssobczak 2011 년

2
이 기술은 생성 된 뷰가 저장 프로 시저에 전달 된 varchar에 종속 된 경우 저장 프로 시저 내에서 뷰를 만들 때 작동합니다. 이 경우에는 '@ p1 = 12;'로 설정해야했습니다. 보기를 만들기 위해 호출하기 전에 줄에.
Clayton Stanley

2
여러 데이터베이스 테넌트가이 코드를 동시에 호출하는 경우 문제 (테넌트 데이터 혼동)가 발생할 가능성이 있습니까?
Gruber 2013 년

2
@Mr_and_Mrs_D 파생 테이블에는 별칭이 필요합니다. 당신은 당신이 원하는대로 호출 할 수 있습니다,하지만 당신은 그것을 생략 할 수 없습니다
로빈 저울

4
변수 p1은 그 이후의 값을 유지하므로 매개 변수를 전달하지 않고 뷰를 다시 사용하면 전달 된 이전 뷰를 사용하므로 혼란 스러울 수 있습니다! 다음과 같이 사용한 후에 "지울"수 있습니다. select s. * from (select p1 : = 12 p) pass, h_parm s, (select @ p1 : =-1) clear; (이 목적에 대해 -1이 유효하지 않은 값이라고 가정)
BuvinJ dec

21
CREATE VIEW MyView AS
   SELECT Column, Value FROM Table;


SELECT Column FROM MyView WHERE Value = 1;

MySQL의 적절한 솔루션이며 다른 SQL을 사용하면 뷰를 더 정확하게 정의 할 수 있습니다.

참고 :보기가 매우 복잡하지 않으면 MySQL은이를 잘 최적화합니다.


1
내 경우에는 매개 변수를 사용하려는 WHERE 부분이 neasted select에 있으므로 뷰 외부에서 필터링하는 것은 불가능합니다.
ssobczak

실제로 neasted select는 뷰에서 허용되지 않지만 두 뷰로 분할했습니다. V1은 데이터를 필터링하고 집계하며 V1 위에 V2가 있습니다. 외부 V1의 데이터는 집계 된 것으로 표시되므로 외부 (V2)의 데이터를 필터링 할 수 없습니다.
ssobczak

2
그런 다음 정확한 제어가 필요한 경우 매번 전체 쿼리를 작성하거나 저장 프로 시저 내에서 쿼리를 작성해야하는 경우보기를 전혀 사용하지 마십시오. 보기로 저장하는 것은 무의미 해 보입니다. 당신이 달성하려는 쿼리를 게시하면 누군가가 다른 / 더 나은 경로를 제안 할 수 있습니다.
MindStalker

간단한 질문이 상당히 복잡해지기 때문에이 작업을하고 싶지 않았지만 유용하다고 생각되면 시도해 보겠습니다.
ssobczak

이 형식을 사용하면 매개 변수에 따라 결과 세트 또는 테이블 이름을 변경할 수 없습니다
MMEL

1

이전에 저장 프로 시저를 사용하지 않고 대신 매개 변수 테이블과 connection_id () 마법을 사용하는 다른 해결 방법을 생각해 냈습니다.

편집 (댓글에서 복사)

라는 열을 포함하는 테이블을 만듭니다 connection_id(bigint로 만듭니다). 해당 테이블에보기에 대한 매개 변수 열을 배치하십시오. 에 기본 키를 넣습니다 connection_id. 매개 변수 테이블로 바꾸고 사용 CONNECTION_ID()하여 connection_id 값을 채우십시오. 뷰에서 매개 변수 테이블에 대한 교차 조인을 사용하고 WHERE param_table.connection_id = CONNECTION_ID(). 이것은 당신이 원하는 매개 변수 테이블의 한 행과 만 교차 결합합니다. 그런 다음 where 절의 다른 열을 사용할 수 있습니다 (예 : where) orders.order_id = param_table.order_id.


5
어느 것? 더 알려주세요.
marzapower

1
connection_id라는 열을 포함하는 테이블을 만듭니다 (bigint로 만듭니다). 해당 테이블에보기에 대한 매개 변수 열을 배치하십시오. connection_id에 기본 키를 넣으십시오. 매개 변수 테이블로 바꾸고 CONNECTION_ID ()를 사용하여 connection_id 값을 채 웁니다. 뷰에서 매개 변수 테이블에 대한 교차 조인을 사용하고 WHERE param_table.connection_id = CONNECTION_ID ()를 입력합니다. 이것은 당신이 원하는 매개 변수 테이블의 한 행과 만 교차 결합합니다. 그런 다음 where 절의 다른 열을 사용할 수 있습니다 (예 : orders.order_id = param_table.order_id).
Justin Swanhart 2013 년

KLUDGE! 하지만 귀여워.
릭 제임스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.