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

विभिन्न चयन प्रश्नों के आउटपुट को वापस करने के लिए पीएल/पीजीएसक्यूएल फ़ंक्शन को दोबारा दोहराएं

डायनामिक एसक्यूएल और RETURN टाइप करें


आप डायनामिक SQL निष्पादित करना चाहते हैं . मूल रूप से, EXECUTE की सहायता से plpgsql में यह आसान है . आपको ज़रूरत नहीं एक कर्सर। वास्तव में, ज्यादातर समय आप स्पष्ट कर्सर के बिना बेहतर होते हैं।

आप जिस समस्या का सामना कर रहे हैं:आप अभी तक अपरिभाषित प्रकार के रिकॉर्ड वापस करना चाहते हैं . किसी फ़ंक्शन को RETURN . में अपना रिटर्न प्रकार घोषित करने की आवश्यकता होती है क्लॉज (या OUT . के साथ) या INOUT पैरामीटर)। आपके मामले में आपको गुमनाम रिकॉर्ड पर वापस जाना होगा, क्योंकि संख्या , नाम और प्रकार लौटाए गए कॉलम अलग-अलग होते हैं। पसंद:

CREATE FUNCTION data_of(integer)
  RETURNS SETOF record AS ...

हालांकि, यह विशेष रूप से उपयोगी नहीं है। आपको प्रत्येक कॉल के साथ कॉलम परिभाषा सूची प्रदान करनी होगी। पसंद:

SELECT * FROM data_of(17)
AS foo (colum_name1 integer
      , colum_name2 text
      , colum_name3 real);

लेकिन आप यह भी कैसे करेंगे, जब आप पहले से कॉलम नहीं जानते हैं?
आप कम संरचित दस्तावेज़ डेटा प्रकारों जैसे json का उपयोग कर सकते हैं , jsonb , hstore या xml . देखें:

  • डेटाबेस में डेटा टेबल कैसे स्टोर करें?

लेकिन, इस प्रश्न के प्रयोजन के लिए, मान लें कि आप यथासंभव व्यक्तिगत, सही ढंग से टाइप किए गए और नामित कॉलम वापस करना चाहते हैं।

निश्चित रिटर्न प्रकार के साथ सरल समाधान

कॉलम datahora एक दिया हुआ प्रतीत होता है, मैं मान लूंगा डेटा प्रकार timestamp और यह कि अलग-अलग नाम और डेटा प्रकार वाले हमेशा दो और कॉलम होते हैं।

नाम हम रिटर्न प्रकार में सामान्य नामों के पक्ष में छोड़ देंगे।
प्रकार हम भी छोड़ देंगे, और सभी को text पर डाल देंगे चूंकि हर डेटा प्रकार को text में डाला जा सकता है ।

CREATE OR REPLACE FUNCTION data_of(_id integer)
  RETURNS TABLE (datahora timestamp, col2 text, col3 text)
  LANGUAGE plpgsql AS
$func$
DECLARE
   _sensors text := 'col1::text, col2::text';  -- cast each col to text
   _type    text := 'foo';
BEGIN
   RETURN QUERY EXECUTE '
      SELECT datahora, ' || _sensors || '
      FROM   ' || quote_ident(_type) || '
      WHERE  id = $1
      ORDER  BY datahora'
   USING  _id;
END
$func$;

चर _sensors और _type इसके बजाय इनपुट पैरामीटर हो सकते हैं।

RETURNS TABLE पर ध्यान दें खंड।

RETURN QUERY EXECUTE . के उपयोग पर ध्यान दें . डायनामिक क्वेरी से पंक्तियों को वापस करने के लिए यह अधिक शानदार तरीकों में से एक है।

मैं फ़ंक्शन पैरामीटर के लिए एक नाम का उपयोग करता हूं, बस USING . बनाने के लिए RETURN QUERY EXECUTE . का क्लॉज कम भ्रमित। $1 SQL-स्ट्रिंग में फ़ंक्शन पैरामीटर को संदर्भित नहीं करता है बल्कि USING . के साथ पास किए गए मान को संदर्भित करता है खंड। (दोनों $1 . होते हैं इस सरल उदाहरण में उनके संबंधित क्षेत्र में।)

_sensors . के लिए उदाहरण मान नोट करें :प्रत्येक कॉलम को text type टाइप करने के लिए कास्ट किया जाता है ।

इस प्रकार का कोड SQL इंजेक्शन के लिए बहुत संवेदनशील है . मैं quote_ident() use का इस्तेमाल करता हूं इससे बचाव के लिए। वेरिएबल _sensors . में कुछ कॉलम नामों को एक साथ लंपिंग करना quote_ident() . के इस्तेमाल को रोकता है (और आमतौर पर एक बुरा विचार है!) सुनिश्चित करें कि किसी अन्य तरीके से कोई खराब सामग्री नहीं हो सकती है, उदाहरण के लिए अलग-अलग कॉलम नामों को quote_ident() के माध्यम से चलाकर बजाय। एक VARIADIC पैरामीटर दिमाग में आता है ...

PostgreSQL 9.1 के बाद से आसान

संस्करण 9.1 या बाद के संस्करण के साथ आप format() . का उपयोग कर सकते हैं और सरल बनाने के लिए:

RETURN QUERY EXECUTE format('
   SELECT datahora, %s  -- identifier passed as unescaped string
   FROM   %I            -- assuming the name is provided by user
   WHERE  id = $1
   ORDER  BY datahora'
  ,_sensors, _type)
USING  _id;

फिर से, अलग-अलग कॉलम नाम ठीक से बच सकते हैं और यह साफ तरीका होगा।

समान प्रकार साझा करने वाले स्तंभों की परिवर्तनीय संख्या

आपके प्रश्न अपडेट के बाद ऐसा लगता है कि आपके रिटर्न प्रकार में

. है
  • एक चर संख्या स्तंभों की
  • लेकिन सभी कॉलम एक जैसे टाइप double precision (उपनाम float8 )

ARRAY का उपयोग करें इस मामले में मानों की एक चर संख्या को नेस्ट करने के लिए टाइप करें। इसके अतिरिक्त, मैं कॉलम नामों के साथ एक सरणी लौटाता हूं:

CREATE OR REPLACE FUNCTION data_of(_id integer)
  RETURNS TABLE (datahora timestamp, names text[], values float8[])
  LANGUAGE plpgsql AS
$func$
DECLARE
   _sensors text := 'col1, col2, col3';  -- plain list of column names
   _type    text := 'foo';
BEGIN
   RETURN QUERY EXECUTE format('
      SELECT datahora
           , string_to_array($1)  -- AS names
           , ARRAY[%s]            -- AS values
      FROM   %s
      WHERE  id = $2
      ORDER  BY datahora'
    , _sensors, _type)
   USING  _sensors, _id;
END
$func$;

विभिन्न पूर्ण तालिका प्रकार

वास्तव में तालिका के सभी कॉलम को वापस करने के लिए , बहुरूपी प्रकार . का उपयोग करके एक सरल, शक्तिशाली समाधान है :

CREATE OR REPLACE FUNCTION data_of(_tbl_type anyelement, _id int)
  RETURNS SETOF anyelement
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE format('
      SELECT *
      FROM   %s  -- pg_typeof returns regtype, quoted automatically
      WHERE  id = $1
      ORDER  BY datahora'
    , pg_typeof(_tbl_type))
   USING  _id;
END
$func$;

कॉल करें (महत्वपूर्ण!):

SELECT * FROM data_of(NULL::pcdmet, 17);

pcdmet बदलें किसी अन्य तालिका नाम के साथ कॉल में।

यह कैसे काम करता है?

anyelement एक छद्म डेटा प्रकार, एक बहुरूपी प्रकार, किसी भी गैर-सरणी डेटा प्रकार के लिए प्लेसहोल्डर है। anyelement . की सभी घटनाएं फ़ंक्शन में रन टाइम पर प्रदान किए गए उसी प्रकार का मूल्यांकन करें। फ़ंक्शन के तर्क के रूप में परिभाषित प्रकार के मान की आपूर्ति करके, हम परोक्ष रूप से रिटर्न प्रकार को परिभाषित करते हैं।

PostgreSQL स्वचालित रूप से बनाई गई प्रत्येक तालिका के लिए एक पंक्ति प्रकार (एक समग्र डेटा प्रकार) को परिभाषित करता है, इसलिए प्रत्येक तालिका के लिए एक अच्छी तरह से परिभाषित प्रकार होता है। इसमें अस्थायी टेबल शामिल हैं, जो तदर्थ उपयोग के लिए सुविधाजनक है।

कोई भी प्रकार NULL हो सकता है . एक NULL में हाथ डालें मान, तालिका के प्रकार पर डाला गया:NULL::pcdmet

अब फ़ंक्शन एक अच्छी तरह से परिभाषित पंक्ति प्रकार देता है और हम SELECT * FROM data_of() का उपयोग कर सकते हैं पंक्ति को विघटित करने और अलग-अलग कॉलम प्राप्त करने के लिए।

pg_typeof(_tbl_type) तालिका का नाम वस्तु पहचानकर्ता प्रकार regtype . के रूप में देता है . जब स्वचालित रूप से text में परिवर्तित हो जाता है , पहचानकर्ता स्वचालित रूप से दोहरे-उद्धृत और स्कीमा-योग्य हैं यदि आवश्यक हो, तो स्वचालित रूप से SQL इंजेक्शन से बचाव करें। यह स्कीमा-योग्य तालिका-नामों से भी निपट सकता है जहां quote_ident() विफल हो जाएगा। देखें:

  • तालिका नाम PostgreSQL फ़ंक्शन पैरामीटर के रूप में


  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 में हर शब्द के पहले अक्षर को कैपिटलाइज़ कैसे करें

  3. 2d सरणी से 1d सरणी का चयन कैसे करें?

  4. रेल + पोस्टग्रेज ड्रॉप त्रुटि:डेटाबेस को अन्य उपयोगकर्ताओं द्वारा एक्सेस किया जा रहा है

  5. sqlalchemy के साथ प्रति-अनुरोध के आधार पर डेटाबेस इंजन को गतिशील रूप से कैसे बांधें