2012-01-04 7 views
13

में एएन क्लॉज का उपयोग करने पर मार्गदर्शन मैं समझता हूं कि रिकर्सिव प्रश्नों (!!) के लिए WITH खंड का उपयोग कैसे करें, लेकिन मुझे इसके सामान्य उपयोग/शक्ति को समझने में समस्याएं आ रही हैं।एसक्यूएल

update global.prospect psp 
set status=status||'*' 
where psp.psp_id=(
      select p2.psp_id 
      from global.prospect p2 
      where p2.status='new' or p2.status='reset' 
      order by p2.request_ts 
      limit 1) 
returning psp.*; 

यह एक WITH बजाय आवरण प्रयोग करने के लिए एक अच्छे उम्मीदवार होगा:

उदाहरण के लिए निम्न क्वेरी एक रिकॉर्ड जिसका आईडी टाइमस्टैम्प द्वारा पहले रिकॉर्ड की आईडी लौटने एक सबक्वेरी का उपयोग करके निर्धारित किया जाता है अद्यतन करता है अपेक्षाकृत बदसूरत उप-क्वेरी? यदि हां, तो क्यों?

+0

प्रलेखन के अनुसार, 'IN [RECURSIVE] '' INSERT' और 'UPDATE' कथन का उपयोग करके PostgreSQL 9.1 में जोड़ा गया था। –

+0

@ जॉयएडम्स - डीएमएल के साथ उपयोग - प्याज की एक और परत –

उत्तर

18

समवर्ती लेखन पहुँच शामिल तालिकाओं के लिए नहीं हो सकता है, वहाँ ऊपर निम्नलिखित प्रश्नों में दौड़ की स्थिति है। पर विचार करें:


आपका उदाहरण एक CTE (आम तालिका अभिव्यक्ति) का उपयोग कर सकते हैं, लेकिन यह आप कुछ भी नहीं एक सबक्वेरी नहीं कर सका दे देंगे:

WITH x AS (
    SELECT psp_id 
    FROM global.prospect 
    WHERE status IN ('new', 'reset') 
    ORDER BY request_ts 
    LIMIT 1 
    ) 
UPDATE global.prospect psp 
SET status = status || '*' 
FROM x 
WHERE psp.psp_id = x.psp_id 
RETURNING psp.*; 

बीटीडब्ल्यू, लौटाई गई पंक्ति संस्करण अपडेट की जाएगी।


तो यदि आप किसी अन्य तालिका में लौटे पंक्ति सम्मिलित करना चाहता था, कि जहां खंड के साथ एक आवश्यक हो जाता है है:

WITH x AS (
    SELECT psp_id 
    FROM global.prospect 
    WHERE status IN ('new', 'reset') 
    ORDER BY request_ts 
    LIMIT 1 
    ), y AS (
    UPDATE global.prospect psp 
    SET status = status || '*' 
    FROM x 
    WHERE psp.psp_id = x.psp_id 
    RETURNING psp.* 
    ) 
INSERT INTO z 
SELECT * 
FROM y 

डाटा को संशोधित करने CTE का उपयोग करके क्वेरी PostgreSQL 9.1 या बाद के साथ संभव हो रहे हैं।
more in the excellent manual पढ़ें।

+0

वाह - वास्तव में अच्छा - धन्यवाद। पीजी डॉक्टर की गुणवत्ता के साथ सहमत हैं, लेकिन आज तक सीटीई उन चीजों में से एक रहा है जो मैंने इसके बारे में पढ़ते समय शांत महसूस किया है, लेकिन अभ्यास में कभी भी इसका संचालन नहीं हुआ है। आपके दो उदाहरण (मुझे लगता है!) बहुत मदद करता है –

9

WITH आपको SELECT क्वेरी में उपयोग के लिए "अस्थायी तालिकाओं" को परिभाषित करने देता है। उदाहरण के लिए, मैं हाल ही में इस तरह एक प्रश्न लिखा था, दो सेट के बीच परिवर्तन की गणना करने के:

-- Let o be the set of old things, and n be the set of new things. 
WITH o AS (SELECT * FROM things(OLD)), 
    n AS (SELECT * FROM things(NEW)) 

-- Select both the set of things whose value changed, 
-- and the set of things in the old set but not in the new set. 
SELECT o.key, n.value 
    FROM o 
    LEFT JOIN n ON o.key = n.key 
    WHERE o.value IS DISTINCT FROM n.value 

UNION ALL 

-- Select the set of things in the new set but not in the old set. 
SELECT n.key, n.value 
    FROM o 
    RIGHT JOIN n ON o.key = n.key 
    WHERE o.key IS NULL; 

शीर्ष पर "टेबल" को परिभाषित करने o और n, मैं भाव things(OLD) और things(NEW) दोहराने से बचें करने में सक्षम था।

निश्चित रूप से, हम शायद को FULL JOIN का उपयोग करके समाप्त कर सकते हैं, लेकिन मैं अपने विशेष मामले में ऐसा करने में सक्षम नहीं था।


अगर मैं आपकी क्वेरी सही ढंग से समझ, यह करता है यह:

  • global.prospect जिसकी स्थिति 'नए' या 'रीसेट' है में सबसे पुराना पंक्ति का पता लगाएं।

  • मार्क यह अपनी स्थिति

  • वापसी पंक्ति (status के लिए हमारी ट्वीक सहित) के लिए एक तारक जोड़कर।

मुझे नहीं लगता कि WITH आपके मामले में कुछ भी सरल करेगा। यह थोड़ा और अधिक एक FROM खंड का उपयोग करने के सुरुचिपूर्ण है, हालांकि हो सकता है:

update global.prospect psp 
set status = status || '*' 
from (select psp_id 
     from global.prospect 
     where status = 'new' or status = 'reset' 
     order by request_ts 
     limit 1 
     ) p2 
where psp.psp_id = p2.psp_id 
returning psp.*; 

untested है। अगर यह काम करता है तो मुझे बताएं।

यह काफी वास्तव में क्या आप पहले से ही है, को छोड़कर है:

  • यह आसानी से अनेक पंक्तियां अपडेट करने के लिए बढ़ाया जा सकता है। आपके संस्करण में, जो सबक्वायरी अभिव्यक्ति का उपयोग करता है, यदि क्वेरी कई पंक्तियों को उत्पन्न करने के लिए बदल जाती है तो क्वेरी विफल हो जाएगी।

  • मैंने subquery में global.prospect उपनाम नहीं किया था, इसलिए इसे पढ़ने में थोड़ा आसान है। चूंकि यह FROM खंड का उपयोग करता है, इसलिए यदि आप गलती से तालिका को अपडेट किया जा रहा है तो आपको एक त्रुटि मिलेगी।

  • आपके संस्करण में, सबकुरी अभिव्यक्ति प्रत्येक आइटम के लिए सामने आती है। हालांकि PostgreSQL को इसे अनुकूलित करना चाहिए और केवल एक बार अभिव्यक्ति का मूल्यांकन करना चाहिए, यदि आप गलती से psp में कॉलम का संदर्भ देते हैं या अस्थिर अभिव्यक्ति जोड़ते हैं तो यह अनुकूलन दूर हो जाएगा।

+0

को समझने के लिए एकाधिक पंक्तियों को अपडेट करने के लिए, किसी को किसी भी प्रकार की सबक्वायरी या सीटीई की आवश्यकता नहीं होगी, बस: 'वैश्विक अद्यतन करें। प्रॉस्पेक्ट एसईटी स्थिति = स्थिति || '*' जहां स्थिति ('नया', 'रीसेट') लौटने * * ' –