MySQL'de parametre ile görünüm oluşturabilir miyim?


94

Bunun gibi bir görüşüm var:

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

Daha genel hale getirmek istiyorum, bu 2'yi bir değişkene dönüştürmek anlamına geliyor. Bunu denedim:

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

Ancak MySQL buna izin vermiyor.

Çirkin bir çözüm buldum:

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

Ve sonra görüş:

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

Ama gerçekten berbat görünüyor ve kullanımı da berbat - görünümün her kullanımından önce @MyVariable'ı ayarlamam gerekiyor.

Bunun gibi kullanabileceğim bir çözüm var mı:

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

Somut durum şu şekildedir: Reddedilen taleple ilgili bilgileri depolayan bir tablom var:

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;

Çokluk, aynı saniyede kaydedilen aynı taleplerin sayısıdır. Reddetmelerin bir listesini görüntülemek istiyorum, ancak bazen uygulama reddedildiğinde emin olmak için birkaç kez yeniden deniyor. Bu nedenle, genellikle, aynı kullanıcı birkaç saniye içinde aynı özelliği 3 kez reddettiğinde, bu aslında bir inkar olur. Bu isteği yerine getirmek için bir tane daha kaynağımız olsaydı, sonraki iki ret olmazdı. Bu nedenle, rapordaki redleri gruplayarak kullanıcının redlerin gruplanması gereken zaman aralığını belirlemesine izin vermek istiyoruz. Örneğin, zaman damgalarında (1. özellikte 1. kullanıcı için) redler varsa: 1,2,24,26,27,45 ve kullanıcı 4 saniyeden daha yakın olan redleri gruplamak istiyorsa, şuna benzer bir şey almalıdır: 1 (x2), 24 (x3), 45 (x1). Gerçek inkarlar arasındaki boşlukların, kopyalar arasındaki boşluktan çok daha büyük olduğunu varsayabiliriz.

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;

Ardından, 3. ve 4. özelliklerde kullanıcı 1 ve 2'den gelen redleri her 5 saniyede bir birleştirerek göstermek için yapmanız gereken tek şey:

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

Görünümü kullanıyorum çünkü içinde veriyi filtrelemek ve onu jQuery ızgarasında açıkça kullanmak, otomatik olarak sıralamak, kayıt sayısını sınırlamak vb.

Ancak bu sadece çirkin bir çözüm. Bunu yapmanın uygun bir yolu var mı?

Yanıtlar:


164

Aslında func oluşturursanız:

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

ve görüntüleyin:

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

Daha sonra bir parametreyle bir görünümü çağırabilirsiniz:

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

Umut ediyorum bu yardım eder.


31
Vay canına, bu SQL'de gördüğüm en beceriksiz şeylerden biri;) Ama tam da yapmak istediğim şey buydu.
ssobczak

2
Bu teknik, oluşturulan görünüm saklı yordama geçirilen bir varchar'a bağlı olduğunda, saklı yordam içinde bir görünüm oluştururken çalışır. Bu durumda, 'set @ p1 = 12;' görünümü oluşturmak için çağrıdan önceki hatta.
Clayton Stanley

2
Birkaç veritabanı kiracısı bu kodu aynı anda çağırırsa, herhangi bir sorun potansiyeli var mı (kiracı verilerinin karışması)?
Gruber

2
@Mr_and_Mrs_D türetilmiş tablo bir takma ada ihtiyaç duyar. ona ne istersen diyebilirsin, ama ihmal edemezsin
Robin Kanters

4
P1 değişkeni bundan sonra değerini korur, bu yüzden eğer görünümü parametreyi geçmeden tekrar kullanırsanız, geçilen öncekini kullanır - bu kafa karıştırıcı olabilir! Bunu şu şekilde kullandıktan sonra "temizleyebilirsiniz": s. * İçinden (p1 seçin: = 12 p) pass, h_parm s, (@ p1 seçin: = - 1) temizle; (-1'in bu amaç için geçersiz bir değer olduğunu varsayarsak)
BuvinJ

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


SELECT Column FROM MyView WHERE Value = 1;

MySQL'de doğru çözüm, diğer bazı SQL'ler Görünümleri daha kesin olarak tanımlamanıza izin verir.

Not: Görünüm çok karmaşık olmadığı sürece, MySQL bunu iyi bir şekilde optimize edecektir.


1
Benim durumumda, parametresini kullanmak istediğim WHERE bölümü neasted select içindedir, bu yüzden onu görünümün dışından filtrelemek imkansızdır.
ssobczak

Aslında, görünümlerde hoş olmayan seçimlere izin verilmez, ancak onları iki görünüme ayırdım. V1, verileri filtreler ve toplar ve V1'in üstünde V2 bulunur. Dışından (V2'de) V1'deki verileri filtreleyemiyorum, çünkü dışarıda toplanmış olarak görülebiliyorlar.
ssobczak

2
Daha sonra, tam denetime ihtiyacınız varsa, tüm sorguyu her seferinde derleyin veya sorguyu bir saklı yordamın içinde oluşturun. Görünüm olarak kaydetmek anlamsız görünüyor. Yine de, ulaşmaya çalıştığınız sorguları gönderirseniz, birileri farklı / daha iyi bir yol önerebilir.
MindStalker

Bunu yapmamak istedim, çünkü basit sorumu oldukça karmaşık hale getirecek, ama yararlı olabileceğini düşünüyorsanız, deneyeceğim.
ssobczak

Bu format, bir parametreye bağlı olarak sonuç kümesini veya tablonun adını değiştirmenize izin vermez
MMEL

1

Daha önce, saklı yordamları kullanmayan, bunun yerine bir parametre tablosu ve bazı connection_id () sihri kullanan farklı bir çözüm buldum.

DÜZENLE (Yorumlardan kopyalandı)

adlı bir sütun içeren bir tablo oluşturun connection_id(bunu bir bigint yapın). Görünümün parametreleri için bu tabloya sütunlar yerleştirin. Birincil anahtar koyun connection_id. parametre tablosuna değiştirin CONNECTION_ID()ve connection_id değerini doldurmak için kullanın . Görünümde parametre tablosuna çapraz birleştirme kullanın ve koyun WHERE param_table.connection_id = CONNECTION_ID(). Bu, istediğiniz parametre tablosundan sadece bir satır ile çapraz birleşim sağlayacaktır. Daha sonra where cümlesindeki diğer sütunları kullanabilirsiniz, örneğin where orders.order_id = param_table.order_id.


5
Hangisi? Lütfen bize daha fazlasını söyleyin.
marzapower

1
connection_id adlı bir sütun içeren bir tablo oluşturun (bunu bir bigint yapın). Görünümün parametreleri için bu tabloya sütunlar yerleştirin. Connection_id'ye bir birincil anahtar koyun. parametre tablosuyla değiştirin ve connection_id değerini doldurmak için CONNECTION_ID () kullanın. Görünümde parametre tablosuna çapraz birleştirme kullanın ve WHERE param_table.connection_id = CONNECTION_ID () koyun. Bu, istediğiniz parametre tablosundan sadece bir satır ile çapraz birleşim sağlayacaktır. Daha sonra, where cümlesindeki diğer sütunları kullanabilirsiniz, örneğin, burada orders.order_id = param_table.order_id.
Justin Swanhart

KLUDGE! Fakat sevimli.
Rick James
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.