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

जब कोई कॉलम मौजूद नहीं होता है तो पोस्टग्रेज़ एक डिफ़ॉल्ट मान लौटाता है

क्यों करता है रोवन की हैक काम (ज्यादातर)?

SELECT id, title
     , CASE WHEN extra_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN (
   SELECT EXISTS (
      SELECT FROM information_schema.columns 
      WHERE  table_name = 'tbl'
      AND    column_name = 'extra')
   ) AS extra(extra_exists)

सामान्य तौर पर, यह बिल्कुल भी काम नहीं करेगा। पोस्टग्रेज़ SQL कथन को पार्स करता है और एक अपवाद फेंकता है यदि कोई शामिल स्तंभों में से मौजूद नहीं है।

चाल एक तालिका नाम (या उपनाम) को उसी नाम से पेश करना है जो प्रश्न में कॉलम नाम के रूप में है। extra इस मामले में। प्रत्येक तालिका नाम को समग्र रूप से संदर्भित किया जा सकता है, जिसके परिणामस्वरूप पूरी पंक्ति को record प्रकार के रूप में वापस किया जा सकता है . और चूंकि हर प्रकार को text . में डाला जा सकता है , हम इस पूरे रिकॉर्ड को text . में डाल सकते हैं . इस तरह, Postgres क्वेरी को मान्य मान लेता है।

चूंकि स्तंभ नामों को तालिका नामों पर प्राथमिकता दी जाती है, extra::text कॉलम के रूप में व्याख्या की जाती है tbl.extra यदि कॉलम मौजूद है। अन्यथा, यह तालिका की पूरी पंक्ति extra को वापस करने के लिए डिफ़ॉल्ट होगा - जो कभी नहीं होता।

extra . के लिए कोई भिन्न तालिका उपनाम चुनने का प्रयास करें खुद देखने के लिए।

यह एक गैर-दस्तावेज हैक है और टूट सकता है अगर पोस्टग्रेज भविष्य के संस्करणों में एसक्यूएल स्ट्रिंग्स को पार्स किए जाने के तरीके को बदलने का फैसला करता है - भले ही यह असंभव लगता है।

स्पष्ट

यदि आप इसका उपयोग करने का निर्णय लेते हैं, कम से कम इसे स्पष्ट करें

अकेले एक टेबल नाम अद्वितीय नहीं है। "tbl" नाम की एक तालिका एक ही डेटाबेस के कई स्कीमा में कई बार मौजूद हो सकती है, जिससे बहुत भ्रमित और पूरी तरह से गलत परिणाम हो सकते हैं। आपको जरूरत अतिरिक्त रूप से स्कीमा नाम प्रदान करने के लिए:

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN (
   SELECT EXISTS (
      SELECT FROM information_schema.columns 
      WHERE  table_schema = 'public'
      AND    table_name = 'tbl'
      AND    column_name = 'extra'
      ) AS col_exists
   ) extra;

तेज़

चूंकि यह प्रश्न अन्य आरडीबीएमएस के लिए शायद ही पोर्टेबल है, मैं का उपयोग करने का सुझाव देता हूं। सूची तालिका pg_attribute जानकारी स्कीमा के बजाय information_schema.columns . देखें . लगभग 10 गुना तेज।

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN (
   SELECT EXISTS (
      SELECT FROM pg_catalog.pg_attribute
      WHERE  attrelid = 'myschema.tbl'::regclass  -- schema-qualified!
      AND    attname  = 'extra'
      AND    NOT attisdropped    -- no dropped (dead) columns
      AND    attnum   > 0        -- no system columns
      )
   ) extra(col_exists);

साथ ही regclass के लिए अधिक सुविधाजनक और सुरक्षित कास्ट का उपयोग करना . देखें:

आप Postgres को किसी . को मूर्ख बनाने के लिए आवश्यक उपनाम संलग्न कर सकते हैं तालिका, प्राथमिक तालिका सहित। आपको किसी अन्य संबंध में शामिल होने की बिल्कुल भी आवश्यकता नहीं है, जो सबसे तेज़ होना चाहिए:

SELECT id, title
     , CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_attribute
                         WHERE  attrelid = 'tbl'::regclass
                         AND    attname  = 'extra'
                         AND    NOT attisdropped
                         AND    attnum   > 0)
            THEN extra::text
            ELSE 'default' END AS extra
FROM   tbl AS extra;

सुविधा

You could encapsulate the test for existence in a simple SQL function (once), arriving (almost) at the function you have been asking for:

CREATE OR REPLACE FUNCTION col_exists(_tbl regclass, _col text)
  RETURNS bool
  LANGUAGE sql STABLE AS
$func$
SELECT EXISTS (
   SELECT FROM pg_catalog.pg_attribute
   WHERE  attrelid = $1
   AND    attname  = $2
   AND    NOT attisdropped
   AND    attnum   > 0
   )
$func$;

COMMENT ON FUNCTION col_exists(regclass, text) IS
'Test for existence of a column. Returns TRUE / FALSE.
$1 .. exact table name (case sensitive!), optionally schema-qualified
$2 .. exact column name (case sensitive!)';

क्वेरी को सरल करता है:

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN col_exists('tbl', 'extra') AS extra(col_exists);

यहां अतिरिक्त संबंध के साथ फ़ॉर्म का उपयोग करना, क्योंकि यह फ़ंक्शन के साथ तेज़ हो गया है।

फिर भी, आपको केवल पाठ्य प्रस्तुति . मिलता है इनमें से किसी भी प्रश्न के साथ कॉलम का। वास्तविक प्रकार . प्राप्त करना इतना आसान नहीं है ।

बेंचमार्क

मैंने इन्हें सबसे तेज़ खोजने के लिए पृष्ठ 9.1 और 9.2 पर 100k पंक्तियों के साथ एक त्वरित बेंचमार्क चलाया:

सबसे तेज़:

SELECT id, title
     , CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_attribute
                         WHERE  attrelid = 'tbl'::regclass
                         AND    attname  = 'extra'
                         AND    NOT attisdropped
                         AND    attnum   > 0)
            THEN extra::text
            ELSE 'default' END AS extra
FROM   tbl AS extra;

दूसरा सबसे तेज़:

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN col_exists('tbl', 'extra') AS extra(col_exists);

db<>fiddle यहां
पुराना sqlfiddle



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostGIS - मल्टीप्लगॉन को सिंगल पॉलीगॉन में बदलें

  2. कैसे Acos () PostgreSQL में काम करता है

  3. ऐसे कॉलम ढूँढना जो PostgreSQL में NULL नहीं हैं

  4. क्या मामला तब मायने रखता है जब 'ऑटो' S3 से डेटा को Redshift तालिका में लोड कर रहा हो?

  5. एरलांग और पोस्टग्रेएसक्यूएल