PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

पोस्टग्रेज में कॉम्बिनेटरिक्स फंक्शन कैसे लिखें?

जब मैं इस पर सो गया तो मेरे पास एक बिल्कुल नया, सरल, तेज़ विचार था:

CREATE OR REPLACE FUNCTION f_combos(_arr anyarray)
  RETURNS TABLE (combo anyarray) LANGUAGE plpgsql AS
$BODY$
BEGIN
    IF array_upper(_arr, 1) IS NULL THEN
        combo := _arr; RETURN NEXT; RETURN;
    END IF;

    CASE array_upper(_arr, 1)
--  WHEN 0 THEN -- does not exist
    WHEN 1 THEN
        RETURN QUERY VALUES ('{}'), (_arr);
    WHEN 2 THEN
        RETURN QUERY VALUES ('{}'), (_arr[1:1]), (_arr), (_arr[2:2]);
    ELSE
        RETURN QUERY
        WITH x AS (
            SELECT f.combo FROM f_combos(_arr[1:array_upper(_arr, 1)-1]) f
            )
        SELECT x.combo FROM x
        UNION ALL
        SELECT x.combo || _arr[array_upper(_arr, 1)] FROM x;
    END CASE;
END
$BODY$;

कॉल करें:

SELECT * FROM f_combos('{1,2,3,4,5,6,7,8,9}'::int[]) ORDER BY 1;

512 पंक्तियाँ, कुल रनटाइम:2.899 एमएस

व्याख्या करें

  • विशेष मामलों का इलाज NULL के साथ करें और खाली सरणी।
  • दो की एक आदिम सरणी के लिए संयोजन बनाएं।
  • किसी भी लंबी सरणी को निम्न में विभाजित किया गया है:
    • लंबाई n-1 की समान सरणी के लिए संयोजन
    • साथ ही वे सभी तत्व n के साथ संयुक्त हैं .. पुनरावर्ती

वास्तव में सरल, एक बार मिल जाने के बाद।

  • सबस्क्रिप्ट 1 से शुरू होने वाले 1-आयामी पूर्णांक सरणियों के लिए काम करता है (नीचे देखें)।
  • पुराने सॉल्यूशन से 2-3 गुना तेज, स्केल बेहतर होता है।
  • किसी भी के लिए काम करता है तत्व प्रकार फिर से (बहुरूपी प्रकारों का उपयोग करके)।
  • परिणाम में खाली सरणी शामिल है जैसा कि प्रश्न में दिखाया गया है (और जैसा कि @Craig ने मुझे टिप्पणियों में बताया है)।
  • छोटा, अधिक सुंदर।

यह मानता है सरणी सबस्क्रिप्ट 1 . से शुरू (चूक)। यदि आप अपने मूल्यों के बारे में सुनिश्चित नहीं हैं, तो सामान्य करने के लिए फ़ंक्शन को इस तरह कॉल करें:

SELECT * FROM  f_combos(_arr[array_lower(_arr, 1):array_upper(_arr, 1)]);

सुनिश्चित नहीं है कि सरणी सबस्क्रिप्ट को सामान्य करने का एक और शानदार तरीका है या नहीं। मैंने इसके बारे में एक प्रश्न पोस्ट किया है:1

पुराना समाधान (धीमा)

CREATE OR REPLACE FUNCTION f_combos2(_arr int[], _a int[] = '{}', _z int[] = '{}')
 RETURNS SETOF int[] LANGUAGE plpgsql AS
$BODY$
DECLARE
   i int;
   j int;
   _up int;
BEGIN
   IF array_length(_arr,1) > 0 THEN 
      _up := array_upper(_arr, 1);

      FOR i IN array_lower(_arr, 1) .. _up LOOP
         FOR j IN i .. _up  LOOP
            CASE j-i
            WHEN 0,1 THEN
               RETURN NEXT _a || _arr[i:j] || _z;
            WHEN 2 THEN
               RETURN NEXT _a || _arr[i:i] || _arr[j:j] || _z;
               RETURN NEXT _a || _arr[i:j] || _z;
            ELSE
               RETURN NEXT _a || _arr[i:i] || _arr[j:j] || _z;
               RETURN QUERY SELECT *
               FROM f_combos2(_arr[i+1:j-1], _a || _arr[i], _arr[j] || _z);
            END CASE;
         END LOOP;
      END LOOP;
   ELSE
      RETURN NEXT _arr;
   END IF;
END;
$BODY$;

कॉल करें:

SELECT * FROM f_combos2('{7,15,48}'::int[]) ORDER BY 1;

1-आयामी पूर्णांक सरणियों के लिए काम करता है। इसे और अधिक अनुकूलित किया जा सकता है, लेकिन निश्चित रूप से इस प्रश्न के दायरे के लिए इसकी आवश्यकता नहीं है।
ORDER BY प्रश्न में प्रदर्शित आदेश को लागू करने के लिए।

NULL . के रूप में NULL या खाली सरणी प्रदान करें टिप्पणियों में उल्लेख किया गया है।

PostgreSQL 9.1 के साथ परीक्षण किया गया, लेकिन किसी भी आधे आधुनिक संस्करण के साथ काम करना चाहिए।array_lower() और array_upper() कम से कम PostgreSQL 7.4 के बाद से रहा है। संस्करण 8.4 में केवल पैरामीटर डिफ़ॉल्ट नए हैं। आसानी से बदला जा सकता है।

प्रदर्शन अच्छा है।

SELECT DISTINCT * FROM f_combos('{1,2,3,4,5,6,7,8,9}'::int[]) ORDER BY 1;

511 पंक्तियाँ, कुल रनटाइम:7.729 ms

स्पष्टीकरण

यह इस सरल रूप पर बनाता है जो केवल पड़ोसी तत्वों के सभी संयोजन बनाता है:

CREATE FUNCTION f_combos(_arr int[])
  RETURNS SETOF int[] LANGUAGE plpgsql AS
$BODY$
DECLARE
   i  int;
   j  int;
  _up int;
BEGIN
   _up := array_upper(_arr, 1);

   FOR i in array_lower(_arr, 1) .. _up LOOP
      FOR j in i .. _up LOOP
         RETURN NEXT _arr[i:j];
      END LOOP;
   END LOOP;
END;
$BODY$;

लेकिन यह दो से अधिक तत्वों वाले उप-सरणियों के लिए विफल हो जाएगा। तो:

  • 3 तत्वों के साथ किसी भी उप-सरणी के लिए केवल बाहरी दो तत्वों वाला एक सरणी जोड़ा जाता है। यह इस विशेष मामले के लिए एक शॉर्टकट है जो प्रदर्शन को बेहतर बनाता है और इसकी सख्ती से आवश्यकता नहीं है

  • 3 से अधिक तत्वों वाले किसी भी उप-सरणी के लिए मैं बाहरी दो तत्व . लेता हूं और आंतरिक तत्वों के सभी संयोजन से भरें एक ही फ़ंक्शन द्वारा निर्मित पुनरावर्ती



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. केवल एक ट्रिगर के भीतर से प्रविष्टि की अनुमति दें

  2. PostgreSQL 9.3 में स्विचओवर/स्विचबैक लागू करना।

  3. Django 1.8 माइग्रेशन कॉलम आईडी को पूर्णांक में डालने में असमर्थ

  4. जटिल पासवर्ड के साथ पासवर्ड प्रमाणीकरण विफल हो जाता है

  5. PostgreSQL:42883 ऑपरेटर मौजूद नहीं है:समय क्षेत्र के बिना टाइमस्टैम्प =टेक्स्ट