2012-07-09 12 views
28

मेरे पास नेस्टेड सबक्वायरीज़ की श्रृंखला के माध्यम से 4 टेबलों में फैले मेरे पोस्टग्रेएसक्यूएल डेटाबेस पर एक जटिल क्वेरी है। हालांकि, थोड़ी मुश्किल लग रही उपस्थिति और सेटअप के बावजूद, आखिरकार यह दो बाहरी पैरामीटर (दो तारों को विभिन्न तालिकाओं में फ़ील्ड के साथ मिलान करने की आवश्यकता है) के मिलान के आधार पर दो कॉलम (उसी तालिका से, यदि स्थिति में मदद करता है) वापस कर देगा। मैं PostgreSQL में डेटाबेस डिज़ाइन के लिए बिल्कुल नया हूं, इसलिए मुझे पता है कि यह प्रतीत होता है कि यह प्रतीत होता है कि दृश्यों की तरह जादुई चीज मौजूद है, और ऐसा लगता है कि यह मेरी मदद कर सकता है, लेकिन शायद नहीं।PostgreSQL दृश्य में "WHERE" पैरामीटर में पास करें?

क्या कोई तरीका है कि मैं अपनी जटिल क्वेरी को एक दृश्य में ले जा सकता हूं और किसी भी तरह से इसे दो मानों को पास कर सकता हूं जिन्हें मुझे मिलान करने की आवश्यकता है? इससे फ्रंट-एंड पर मेरे कोड को सरल बना दिया जाएगा (जटिलताओं को डेटाबेस संरचना में स्थानांतरित करके)। मैं एक ऐसा दृश्य बना सकता हूं जो मेरी स्थिर उदाहरण क्वेरी को लपेटता है, और यह ठीक काम करता है, हालांकि यह केवल स्ट्रिंग मानों की एक जोड़ी के लिए काम करता है। मुझे विभिन्न मूल्यों के साथ इसका उपयोग करने में सक्षम होना चाहिए।

इस प्रकार मेरा प्रश्न है: क्या पैरामीटर को अन्यथा स्थिर दृश्य में पार करना संभव है और क्या यह "गतिशील" हो गया है? या शायद एक दृष्टिकोण इसे देखने का सही तरीका नहीं है। अगर कुछ और है जो बेहतर काम करेगा, तो मैं सभी कान हूँ!

* संपादित करें: * के रूप में टिप्पणी में अनुरोध किया है, यहाँ मेरी क्वेरी के रूप में यह अब खड़ा है:

SELECT param_label, param_graphics_label 
    FROM parameters 
WHERE param_id IN 
     (SELECT param_id 
      FROM parameter_links 
      WHERE region_id = 
       (SELECT region_id 
        FROM regions 
        WHERE region_label = '%PARAMETER 1%' AND model_id = 
         (SELECT model_id FROM models WHERE model_label = '%PARAMETER 2%') 
       ) 
     ) AND active = 'TRUE' 
ORDER BY param_graphics_label; 

पैरामीटर ऊपर प्रतिशत प्रतीकों से बंद सेट कर रहे हैं।

+2

यदि आप कुछ कोड टुकड़े पोस्ट करने में सक्षम थे तो यह बेहतर समझने में हमारी सहायता कर सकता है –

उत्तर

39

आप एक सेट पर वापस लौटने समारोह इस्तेमाल कर सकते हैं:

create or replace function label_params(parm1 text, parm2 text) 
    returns table (param_label text, param_graphics_label text) 
as 
$body$ 
    select ... 
    WHERE region_label = $1 
    AND model_id = (SELECT model_id FROM models WHERE model_label = $2) 
    .... 
$body$ 
language sql; 

तो फिर तुम कर सकते हैं:

select * 
from label_params('foo', 'bar') 

Btw:

AND model_id = (SELECT model_id FROM models WHERE model_label = $2) 

अगर model_label नहीं है: क्या आप चाहते हैं अद्वितीय (या प्राथमिक कुंजी) तो यह अंततः एक त्रुटि फेंक देगा। आप शायद चाहते हैं:

AND model_id IN (SELECT model_id FROM models WHERE model_label = $2) 
+1

आप यह अनुमान लगाने में सही हैं कि 'model_label' प्राथमिक कुंजी नहीं है। यह "अद्वितीय होना चाहिए" लेकिन यह आवश्यक रूप से सॉफ्टवेयर लागू नहीं है। ('model_id' 'मॉडल' की प्राथमिक कुंजी है)। जो मुझे याद है, उससे स्विच करने से इस तथ्य को नुकसान नहीं पहुंचाया जाना चाहिए कि मैं केवल एक प्रविष्टि से मेल खाना चाहता हूं, सही? – Devin

+2

@ डेविन: सही, यदि आप इसका उपयोग करते हैं तो यह काम करेगा, भले ही एक से अधिक पंक्ति लौटा दी जाए। यदि नहीं, तो आपको रनटाइम पर एक त्रुटि प्राप्त होगी। –

+1

बहुत बढ़िया, यह ठीक उसी तरह काम करेगा जैसा मुझे इसकी आवश्यकता है। और PostgreSQL कार्यों के बारे में कुछ अच्छा सीखा। आपकी सहायताके लिए धन्यवाद! – Devin

2

मुझे नहीं लगता कि जैसा कि आपने कहा है "गतिशील" दृश्य संभव है।

क्यों संग्रहीत प्रक्रिया नहीं लिखती है जो इसके बजाय 2 तर्क लेती है?

22

क्या @a_horse पहले से ही मंजूरी दे दी के अलावा, आप नेस्टेड सबक्वेरी के बजाय JOIN syntax का उपयोग करके अपने एसक्यूएल को आसान बनाने में कर सकता है। प्रदर्शन समान होगा, लेकिन वाक्यविन्यास प्रबंधन के लिए बहुत छोटा और आसान है।

CREATE OR REPLACE FUNCTION param_labels(_region_label text, _model_label text) 
    RETURNS TABLE (param_label text, param_graphics_label text) AS 
$func$ 
    SELECT p.param_label, p.param_graphics_label 
    FROM parameters  p 
    JOIN parameter_links l USING (param_id) 
    JOIN regions   r USING (region_id) 
    JOIN models   m USING (model_id) 
    WHERE p.active 
    AND r.region_label = $1 
    AND m.model_label = $2 
    ORDER BY p.param_graphics_label; 
$func$ LANGUAGE sql; 
  • तो model_label अद्वितीय नहीं है या क्वेरी में कुछ और डुप्लिकेट पंक्तियों को पैदा करता है, तो आप उस SELECT DISTINCT p.param_graphics_label, p.param_label बनाने के लिए चाहते हो सकता है - सर्वश्रेष्ठ प्रदर्शन के लिए एक मेल ORDER BY खंड के साथ। या GROUP BY खंड का उपयोग करें।

  • Postgres 9.2 जब से तुम एसक्यूएल कार्यों में $1 और $2 के स्थान पर घोषित पैरामीटर नाम का उपयोग कर सकते हैं। (लंबे समय तक पीएल/पीजीएसक्यूएल कार्यों के लिए संभव है)।

  • संघर्ष नामकरण से बचने के लिए देखभाल की जानी चाहिए। यही कारण है कि मैं घोषणा में पैरामीटर नामों को उपसर्ग करने की आदत बना देता हूं (वे फ़ंक्शन के अंदर सबसे अधिक दिखाई दे रहे हैं) और शरीर में तालिका-योग्यता कॉलम नामों को अर्हता प्राप्त करते हैं।

  • मैं WHERE p.active करने के लिए WHERE p.active = 'TRUE' सरलीकृत, क्योंकि स्तंभ active सबसे शायद प्रकार boolean, नहीं text का होना चाहिए।

  • USING केवल तभी काम करता है जब कॉलम नाम जॉइन के बाईं ओर सभी तालिकाओं में स्पष्ट हों। वरना आप अधिक स्पष्ट वाक्य विन्यास का उपयोग करने के लिए है:
    ON l.param_id = p.param_id

+1

ओह वाह, यह बहुत अच्छा है! मुझे पता है कि जॉइन वहां हैं और इस समस्या के लिए आसान रहे होंगे, लेकिन मुझे लगता है कि मैंने कोशिश करने के लिए गम्प्शन को काम नहीं किया है और इसका उपयोग कैसे किया है इसका पता लगाने के लिए। जैसा कि यह पता चला है, यह इतना बुरा नहीं है! – Devin

13

ज्यादातर मामलों में सेट लौटने समारोह जाने का रास्ता है, लेकिन घटना में है कि तुम दोनों पढ़ सकते हैं और सेट करने के लिए लिखना चाहते हैं में, एक दृश्य अधिक उपयुक्त हो सकता है। , इस

SELECT p.param_label, p.param_graphics_label 
    FROM parameters p 
where exists (
    select 1 
    from parameter_links pl 
    where pl.parameter_id = p.id 
    and exists (select 1 from regions r where r.region_id = pl.region_id 
) and p.active = 'TRUE' 
order by p.param_graphics_label; 

मान लिया जाये कि आप विभिन्न आईडी स्तंभों पर अनुक्रमित है: और यह संभव है के लिए एक दृश्य के एक सत्र पैरामीटर को पढ़ने के लिए: के रूप में निम्नलिखित

CREATE VIEW widget_sb AS SELECT * FROM widget WHERE column = cast(current_setting('mydomain.myparam') as int) 

SET mydomain.myparam = 0 
select * from widget_sb 
[results] 

SET mydomain.myparam = 1 
select * from widget_sb 
[distinct results] 
0

मैं क्वेरी अलग तरीके से व्यक्त होता आईएन ऑपरेटर का उपयोग करने से क्वेरी काफी तेज होनी चाहिए; यहां मौजूद पैरामीटर पैरामीटर तालिका से अंतिम डेटा प्राप्त करने के अलावा डेटा तालिका को छूए बिना केवल इंडेक्स वैल्यू का उपयोग करेंगे।

संबंधित मुद्दे