मुझे NULL को कॉलम प्रकार में डालने की आवश्यकता क्यों है?


10

मुझे एक सहायक मिला है जो मेरे लिए बल्क अपडेट करने के लिए कुछ कोड जनरेट कर रहा है और SQL बनाता है जो इस तरह दिखता है:

(दोनों सक्रिय और मुख्य क्षेत्र प्रकार के हैं boolean)

UPDATE fields as t set "active" = new_values."active","core" = new_values."core"
FROM (values 
(true,NULL,3419),
(false,NULL,3420)
) as new_values("active","core","id") WHERE new_values.id = t.id;

हालांकि इसके साथ असफल:

ERROR: column "core" is of type boolean but expression is of type text

मैं इसे ::booleanनल में जोड़कर काम करने के लिए प्राप्त कर सकता हूं , लेकिन यह सिर्फ अजीब लगता है, NULL को प्रकार क्यों माना जाता है TEXT?

इसके अलावा यह थोड़ा मुश्किल है क्योंकि इसे यह जानने के लिए कि इसे किस प्रकार से NULLs (कॉलम की सूची और मानों को वर्तमान में JSON ऑब्जेक्ट्स के एक साधारण सरणी से ऑटोजेनरेटेड किया जा रहा है) को जानने के लिए कोड की थोड़ी सी आवश्यकता होगी। ।

यह क्यों आवश्यक है और क्या एक अधिक सुरुचिपूर्ण समाधान है जिसे NULL के प्रकार को जानने के लिए जनरेटिंग कोड की आवश्यकता नहीं है?

यदि यह प्रासंगिक है, तो मैं ऐसा करने के लिए Node.JS पर सीक्वल का उपयोग कर रहा हूं , लेकिन पोस्टग्रेजेस लाइन क्लाइंट में भी वही परिणाम मिल रहा है।

जवाबों:


16

यह एक दिलचस्प खोज है। आम तौर पर, एक NULL के पास कोई डेटा प्रकार नहीं है, जैसा कि आप यहाँ देख सकते हैं:

SELECT pg_typeof(NULL);

 pg_typeof 
───────────
 unknown

जब VALUESतालिका चित्र में आती है तो यह बदल जाती है :

SELECT pg_typeof(core) FROM (
    VALUES (NULL)
) new_values (core);

 pg_typeof 
───────────
 text

यह व्यवहार https://doxygen.postgresql.org/parse__coerce_8c.html#l01373 पर स्रोत कोड में वर्णित है :

 /*
  * If all the inputs were UNKNOWN type --- ie, unknown-type literals ---
  * then resolve as type TEXT.  This situation comes up with constructs
  * like SELECT (CASE WHEN foo THEN 'bar' ELSE 'baz' END); SELECT 'foo'
  * UNION SELECT 'bar'; It might seem desirable to leave the construct's
  * output type as UNKNOWN, but that really doesn't work, because we'd
  * probably end up needing a runtime coercion from UNKNOWN to something
  * else, and we usually won't have it.  We need to coerce the unknown
  * literals while they are still literals, so a decision has to be made
  * now.
  */

(हां, PostgreSQL स्रोत कोड को समझना आसान है और अधिकांश स्थानों पर, उत्कृष्ट टिप्पणियों के लिए धन्यवाद।)

हालांकि, बाहर का रास्ता निम्नलिखित हो सकता है। मान लें कि आप हमेशा VALUESएक दी गई तालिका के सभी कॉलम से मेल खाते हैं (अन्य मामलों के लिए नीचे दूसरा नोट देखें)। आपके उदाहरण से, एक छोटी सी चाल संभवतः मदद कर सकती है:

SELECT (x).* FROM (VALUES ((TRUE, NULL, 1234)::fields)) t(x);

 active  core   id  
────────┼──────┼──────
 t             1234

यहां आप तालिका के प्रकार पर डाली गई पंक्ति अभिव्यक्तियों का उपयोग करते हैं , और फिर उन्हें एक तालिका में वापस लाते हैं।

उपरोक्त के आधार पर, आपका UPDATEजैसा दिख सकता है

UPDATE fields AS t set active = (x).active, core = (x).core
FROM ( VALUES
           ((true, NULL, 3419)::fields),
           ((false, NULL, 3420)::fields)
     ) AS new_values(x) WHERE (x).id = t.id;

टिप्पणियाँ:

  • मैंने बेहतर मानव पठनीयता के लिए दोहरे उद्धरण चिह्नों को हटा दिया, लेकिन आप उन्हें (कॉलम) नाम बनाते समय मदद कर सकते हैं।
  • यदि आपको केवल कॉलम के सबसेट की आवश्यकता है, तो आप इस उद्देश्य के लिए कस्टम प्रकार बना सकते हैं । उन्हें उसी तरह उपयोग करें जैसे आप ऊपर करेंगे (जहां मैं तालिका के साथ स्वचालित रूप से बनाए गए प्रकार का उपयोग करता हूं, बाद की पंक्ति संरचना को पकड़े हुए)।

Dbfiddle पर काम करने वाली पूरी चीज़ देखें


धन्यवाद, यह दिलचस्प है, हालांकि, मेरे लिए, उपरोक्त कोड Cannot cast type boolean to bigint in column 1(पहले फ़ील्ड स्टेटमेंट के बीच :: पर त्रुटि बिंदु) पैदा करता है
क्रिसजे

1
@ChristopherJ ने fieldsमाना कि टेबल में 3 कॉलम होते हैं, (active, core, id)जिसमें बूलियन, बूलियन और इंट / बिगिंट प्रकार होते हैं। क्या आपकी तालिका में अधिक कॉलम या विभिन्न प्रकार हैं या क्या कॉलम अलग-अलग क्रम में परिभाषित हैं?
ypercube y

आह, मैं देखता हूँ, धन्यवाद, हाँ वहाँ और अधिक कॉलम और अलग क्रम में हैं। मिल गया धन्यवाद
क्रिस जेने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.