Tôi có thể tạo chế độ xem với tham số trong MySQL không?


91

Tôi có một cái nhìn như thế này:

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

Tôi muốn làm cho nó chung chung hơn, có nghĩa là thay đổi 2 thành một biến. Tôi đã thử điều này:

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

Nhưng MySQL không cho phép điều này.

Tôi đã tìm thấy một giải pháp xấu:

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

Và sau đó chế độ xem là:

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

Nhưng nó trông thực sự tồi tệ và việc sử dụng cũng rất tồi tệ - tôi phải đặt @MyVariable trước mỗi lần sử dụng chế độ xem.

Có giải pháp nào mà tôi có thể sử dụng như thế này không:

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

Tình huống cụ thể như sau: Tôi có một bảng lưu trữ thông tin về yêu cầu bị từ chối:

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;

Đa số là một số yêu cầu giống nhau được ghi lại trong cùng một giây. Tôi muốn hiển thị danh sách các từ chối, nhưng đôi khi, khi ứng dụng bị từ chối, nó sẽ thử lại một vài lần chỉ để đảm bảo. Vì vậy, thông thường, khi cùng một người dùng bị từ chối 3 lần trên cùng một tính năng trong vài giây thì đó thực sự là một lần từ chối. Nếu chúng tôi có thêm một tài nguyên, để đáp ứng yêu cầu này, hai lần từ chối tiếp theo sẽ không xảy ra. Vì vậy, chúng tôi muốn nhóm các từ chối trong báo cáo cho phép người dùng chỉ định khoảng thời gian mà các từ chối sẽ được nhóm lại. Ví dụ: nếu chúng tôi có các từ chối (đối với người dùng 1 trên tính năng 1) trong dấu thời gian: 1,2,24,26,27,45 và người dùng muốn nhóm các từ chối gần nhau hơn 4 giây, anh ta sẽ nhận được một cái gì đó như sau: 1 (x2), 24 (x3), 45 (x1). Chúng ta có thể giả định rằng khoảng cách giữa các từ chối thực sự lớn hơn nhiều so với giữa các bản sao.

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;

Sau đó, để hiển thị từ chối từ người dùng 1 và 2 trên các tính năng 3 và 4 được hợp nhất cứ sau 5 giây, tất cả những gì bạn phải làm là:

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

Tôi sử dụng chế độ xem vì nó dễ dàng lọc dữ liệu và sử dụng nó một cách rõ ràng trong lưới jQuery, tự động sắp xếp, giới hạn số lượng bản ghi, v.v.

Nhưng đó chỉ là một cách giải quyết xấu xí. Có một cách thích hợp để làm điều này?

Câu trả lời:


158

Trên thực tế, nếu bạn tạo func:

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

và xem:

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

Sau đó, bạn có thể gọi một chế độ xem với một tham số:

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

Tôi hy vọng nó sẽ giúp.


30
Chà, đây là một trong những thứ khó hiểu nhất mà tôi từng thấy trong SQL;) Nhưng nó chính xác là những gì tôi muốn làm.
ssobczak

2
Kỹ thuật này hoạt động khi tạo một dạng xem trong một thủ tục được lưu trữ, khi dạng xem được tạo phụ thuộc vào một varchar được truyền cho thủ tục được lưu trữ. Trong trường hợp này, tôi phải 'đặt @ p1 = 12;' trên dòng trước cuộc gọi để tạo chế độ xem.
Clayton Stanley

2
Có bất kỳ khả năng xảy ra sự cố (trộn dữ liệu đối tượng thuê) nếu một số đối tượng thuê cơ sở dữ liệu gọi mã này đồng thời không?
Gruber

2
@Mr_and_Mrs_D bảng dẫn xuất cần có bí danh. bạn có thể gọi nó là bất cứ điều gì bạn muốn, nhưng bạn không thể bỏ qua nó
Robin Kanters

4
Biến p1 vẫn giữ nguyên giá trị của nó sau đó, vì vậy nếu bạn sử dụng lại dạng xem mà không truyền tham số, nó sẽ sử dụng dạng trước đã được truyền - điều này có thể gây nhầm lẫn! Bạn có thể "xóa" nó sau khi sử dụng như sau: select s. * From (select p1: = 12 p) pass, h_parm s, (select @ p1: = - 1) clear; (Giả sử -1 là một giá trị không hợp lệ cho mục đích này)
BuvinJ

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


SELECT Column FROM MyView WHERE Value = 1;

Là giải pháp thích hợp trong MySQL, một số SQL khác cho phép bạn định nghĩa Chế độ xem chính xác hơn.

Lưu ý: Trừ khi Chế độ xem rất phức tạp, MySQL sẽ tối ưu hóa điều này tốt.


1
Trong trường hợp của tôi, phần WHERE, trong đó tôi muốn sử dụng tham số nằm trong lựa chọn mới, vì vậy không thể lọc nó từ bên ngoài chế độ xem.
ssobczak

Trên thực tế, các lựa chọn neiled không được phép trong các chế độ xem, nhưng tôi đã chia chúng thành hai chế độ xem. V1 lọc và tổng hợp dữ liệu, và trên đầu V1 có V2. Tôi không thể lọc dữ liệu từ V1 bên ngoài nó (trong V2), vì bên ngoài chúng được hiển thị dưới dạng tổng hợp.
ssobczak

2
Sau đó, hoàn toàn không sử dụng dạng xem, nếu bạn cần kiểm soát chính xác, hãy tạo toàn bộ truy vấn mọi lúc, hoặc tạo truy vấn bên trong một thủ tục được lưu trữ. Lưu dưới dạng xem dường như vô nghĩa. Mặc dù nếu bạn đăng các truy vấn mà bạn đang cố gắng đạt được thì ai đó có thể đề xuất một lộ trình khác / tốt hơn.
MindStalker

Tôi không muốn làm điều này, vì nó sẽ làm cho câu hỏi đơn giản của tôi khá phức tạp, nhưng nếu bạn nghĩ nó có thể hữu ích, tôi sẽ thử.
ssobczak

1

Trước đây tôi đã đưa ra một cách giải quyết khác không sử dụng các thủ tục được lưu trữ mà thay vào đó sử dụng bảng tham số và một số phép thuật connection_id ().

CHỈNH SỬA (Sao chép từ nhận xét)

tạo một bảng có chứa một cột được gọi là connection_id(biến nó thành bigint). Đặt các cột trong bảng đó cho các tham số cho chế độ xem. Đặt một khóa chính trên connection_id. thay thế vào bảng tham số và sử dụng CONNECTION_ID()để điền giá trị connection_id. Trong khung nhìn, sử dụng một phép nối chéo vào bảng tham số và đặt WHERE param_table.connection_id = CONNECTION_ID(). Điều này sẽ kết hợp chéo với chỉ một hàng từ bảng tham số là những gì bạn muốn. Sau đó, bạn có thể sử dụng các cột khác trong mệnh đề where, ví dụ where orders.order_id = param_table.order_id.


5
Cái nào? Vui lòng cho chúng tôi biết thêm điều gì đó.
marzapower

1
tạo một bảng có chứa một cột được gọi là connection_id (biến nó thành bigint). Đặt các cột trong bảng đó cho các tham số cho chế độ xem. Đặt khóa chính trên connection_id. thay thế vào bảng tham số và sử dụng CONNECTION_ID () để điền giá trị connection_id. Trong dạng xem, hãy sử dụng một phép nối chéo vào bảng tham số và đặt WHERE param_table.connection_id = CONNECTION_ID (). Điều này sẽ kết hợp chéo với chỉ một hàng từ bảng tham số là những gì bạn muốn. Sau đó, bạn có thể sử dụng các cột khác trong mệnh đề where, ví dụ: where order.order_id = param_table.order_id.
Justin Swanhart

KHỔNG LỒ! Nhưng dễ thương.
Rick James,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.