क्या मैं MySQL में पैरामीटर के साथ दृश्य बना सकता हूं?


91

मेरे पास इस तरह का एक दृश्य है:

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 (सुविधा 1 पर उपयोगकर्ता 1 के लिए): 1,2,24,26,27,45 है और उपयोगकर्ता 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;

फिर उपयोगकर्ता 3 और 4 पर उपयोगकर्ता 1 और 2 से धारावाहिक दिखाने के लिए आपको हर 5 सेकंड में विलय करना होगा जो आपको करना है:

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

मैं दृश्य का उपयोग करता हूं क्योंकि इसमें डेटा को फ़िल्टर करना आसान है और इसे स्पष्ट रूप से jQuery ग्रिड में उपयोग करना है, स्वचालित रूप से आदेश, रिकॉर्ड की संख्या और इतने पर।

लेकिन यह सिर्फ एक बदसूरत वर्कअराउंड है। क्या ऐसा करने का एक उचित तरीका है?

जवाबों:


158

वास्तव में यदि आप फंक बनाते हैं:

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;

मुझे उम्मीद है यह मदद करेगा।


30
वाह, यह उन सबसे अधिक हैक करने योग्य चीजों में से एक है जो मैंने कभी एसक्यूएल में देखा था;) लेकिन यह वही है जो मैं करना चाहता था।
ssobczak

2
संग्रहीत प्रक्रिया के भीतर दृश्य बनाते समय यह तकनीक काम करती है, जब निर्मित दृश्य संग्रहीत कार्यविधि को पारित किए गए एक varchar पर निर्भर होता है। इस मामले में, मुझे @ p1 = 12 सेट करना था; दृश्य बनाने के लिए कॉल से पहले लाइन पर।
क्लेटन स्टेनली

2
क्या समस्याओं (किरायेदार डेटा मिश्रण) के लिए कोई संभावना है अगर कई डेटाबेस किरायेदार इस कोड को समवर्ती कहते हैं?
ग्रुबर

2
@Mr_and_Mrs_D व्युत्पन्न तालिका को एक उपनाम चाहिए। आप इसे जो चाहें कह सकते हैं, लेकिन आप इसे छोड़ नहीं सकते
रॉबिन कैंटर्स

4
चर p1 इसके बाद अपने मूल्य को बरकरार रखता है, इसलिए यदि आप पैरामीटर को पारित किए बिना फिर से दृश्य का उपयोग करते हैं, तो यह पूर्व पारित एक का उपयोग करेगा - जो शायद भ्रमित हो सकता है! इस तरह से उपयोग करने के बाद आप इसे "साफ़" कर सकते हैं: s का चयन करें। * से (चयन p1: = 12 p) पास, h_parm s, (select @ p1: = - 1) स्पष्ट; (मान लेना -1 इस उद्देश्य के लिए एक अमान्य मूल्य है)
बुविएनजे

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


SELECT Column FROM MyView WHERE Value = 1;

MySQL में उचित समाधान है, कुछ अन्य SQL आपको दृश्य को अधिक सटीक रूप से परिभाषित करने देते हैं।

ध्यान दें: जब तक कि दृश्य बहुत जटिल नहीं है, तब तक MySQL इसे ठीक कर देगा।


1
मेरे मामले में WHERE का हिस्सा, जिसमें मैं पैरामीटर का उपयोग करना चाहता हूं, चयनित चयन में है, इसलिए इसे दृश्य के बाहर से फ़िल्टर करना असंभव है।
ssobczak

वास्तव में नेस्टेड चयनों को विचारों में अनुमति नहीं है, लेकिन मैंने उन्हें दो विचारों में विभाजित किया। V1 फ़िल्टर और डेटा एकत्र करता है, और V1 के शीर्ष पर V2 है। मैं इसे (V2 में) के बाहर V1 से डेटा फ़िल्टर नहीं कर सकता, क्योंकि वे बाहर के रूप में दिखाई दे रहे हैं।
ssobczak

2
फिर हर समय एक दृश्य का उपयोग न करें, यदि आपको सटीक नियंत्रण की आवश्यकता है तो हर बार पूरी क्वेरी बनाएं, या संग्रहीत कार्यविधि के अंदर क्वेरी का निर्माण करें। दृश्य के रूप में सहेजना व्यर्थ लगता है। यद्यपि यदि आप उन प्रश्नों को पोस्ट करते हैं जिन्हें आप प्राप्त करने की कोशिश कर रहे हैं, तो आप एक अलग / बेहतर मार्ग का सुझाव दे सकते हैं।
माइंडस्टल्कर

मैं ऐसा नहीं करना चाहता था, क्योंकि यह मेरे सरल प्रश्न को काफी जटिल बना देगा, लेकिन अगर आपको लगता है कि यह उपयोगी हो सकता है, तो मैं कोशिश करूँगा।
ssobczak

1

मैं पहले एक अलग वर्कअराउंड के साथ आया था जो संग्रहीत प्रक्रियाओं का उपयोग नहीं करता है, लेकिन इसके बजाय एक पैरामीटर तालिका और कुछ कनेक्शन_ () जादू का उपयोग करता है।

EDIT (टिप्पणियों से कॉपी किया गया)

एक तालिका बनाएं जिसमें एक कॉलम होता है जिसे कहा जाता है connection_id(इसे एक बिगिंट बनाएं)। दृश्य के लिए मापदंडों के लिए उस तालिका में कॉलम रखें। पर एक प्राथमिक कुंजी रखो connection_id। पैरामीटर तालिका में बदलें और CONNECTION_ID()connection_id मान को पॉप्युलेट करने के लिए उपयोग करें। दृश्य में पैरामीटर तालिका में एक क्रॉस जॉइन का उपयोग करें और डाल दें WHERE param_table.connection_id = CONNECTION_ID()। यह पैरामीटर तालिका से केवल एक पंक्ति के साथ जुड़ जाएगा जो आप चाहते हैं। आप तब अन्य स्तंभों का उपयोग कर सकते हैं जहां उदाहरण के लिए खंड में जहां orders.order_id = param_table.order_id


5
कौनसा? कृपया हमें कुछ और बताएं।
मार्जापावर

1
एक तालिका बनाएँ जिसमें एक स्तंभ शामिल हो जिसका नाम कनेक्शन_आईडी (इसे बिगिंट बनाएं)। दृश्य के लिए मापदंडों के लिए उस तालिका में कॉलम रखें। Connection_id पर एक प्राथमिक कुंजी रखें। पैरामीटर तालिका में बदलें और कनेक्शन_आईडी मान को पॉप्युलेट करने के लिए CONNECTION_ID () का उपयोग करें। दृश्य में, पैरामीटर तालिका में एक क्रॉस जॉइन का उपयोग करें और WHERE param_table.connection_id = CONNECTION_ID () डालें। यह पैरामीटर तालिका से केवल एक पंक्ति के साथ जुड़ जाएगा जो आप चाहते हैं। फिर आप अन्य कॉलमों का उपयोग कर सकते हैं जहां क्लॉज उदाहरण के लिए जहां ऑर्डर.ऑर्डर_ड = param_table.order_id।
जस्टिन स्वानहार्ट

Kludge! लेकिन प्यारा।
रिक जेम्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.