कैसे jgr सरणी को पोस्टग्रेज सरणी में बदलना है?


69

मेरे पास एक कॉलम dataहै jsonजो इस तरह से एक दस्तावेज़ रखता है :

{
    "name": "foo",
    "tags": ["foo", "bar"]
}

मैं नेस्टेड tagsसरणी को एक संक्षिप्त स्ट्रिंग ( foo, bar) में बदलना चाहता हूं । यह array_to_string()सिद्धांत में कार्य के साथ आसानी से संभव होगा । हालाँकि, यह फ़ंक्शन jsonसरणियों पर कार्य नहीं करता है । तो मुझे आश्चर्य है कि इस jsonसरणी को पोस्टग्रेज में कैसे बदल दिया जाए array?


है json_extract_path_text(your_column, 'tags') आप के लिए क्या देख रहे हैं?
a_horse_with_no_name 21

1
@a_horse_with_no_name: शेष समस्या: सरणी तत्व अभी भी JSON प्रारूप के लिए उद्धृत हैं। पाठ ठीक से नहीं निकाला गया है ...
इरविन ब्रांडस्टेटर

जवाबों:


94

9.4 या नए को पोस्ट करता है

स्पष्ट रूप से इस पोस्ट से प्रेरित , Postgres 9.4 ने लापता फ़ंक्शन (ओं) को जोड़ा:
पैच के लिए लॉरेंस रो और धन्यवाद के लिए एंड्रयू डंस्टन!

JSON सरणी को अनावश्यक करने के लिए। तब का उपयोग array_agg()या एक ARRAY निर्माता एक Postgres का निर्माण करने वालों से। या string_agg()एक text स्ट्रिंग बनाने के लिए ।

एक LATERALया सहसंबद्ध उपश्रेणी में प्रति पंक्ति अनावश्यक तत्वों को एकत्र करें । फिर मूल आदेश संरक्षित है और हम की जरूरत नहीं है ORDER BY, GROUP BYया यहाँ तक कि बाहरी क्वेरी में एक अद्वितीय कुंजी। देख:

jsonbनिम्नलिखित सभी SQL कोड के लिए 'jsonb' के साथ 'json' को बदलें ।

SELECT t.tbl_id, d.list
FROM   tbl t
CROSS  JOIN LATERAL (
   SELECT string_agg(d.elem::text, ', ') AS list
   FROM   json_array_elements_text(t.data->'tags') AS d(elem)
   ) d;

लघु वाक्य रचना:

SELECT t.tbl_id, d.list
FROM   tbl t, LATERAL (
   SELECT string_agg(value::text, ', ') AS list
   FROM   json_array_elements_text(t.data->'tags')  -- col name default: "value"
   ) d;

सम्बंधित:

एआरएवाईवाई सहसंबद्ध उप-निर्माण में:

SELECT tbl_id, ARRAY(SELECT json_array_elements_text(t.data->'tags')) AS txt_arr
FROM   tbl t;

सम्बंधित:

सूक्ष्म अंतर : nullतत्वों को वास्तविक सरणियों में संरक्षित किया जाता है । एक textस्ट्रिंग का निर्माण करने वाले उपरोक्त प्रश्नों में यह संभव नहीं है , जिसमें nullमान शामिल नहीं हो सकते हैं । सच प्रतिनिधित्व एक सरणी है।

समारोह आवरण

बार-बार उपयोग के लिए, इसे और भी सरल बनाने के लिए, किसी फ़ंक्शन में तर्क को इनकैप्सुलेट करें:

CREATE OR REPLACE FUNCTION json_arr2text_arr(_js json)
  RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT json_array_elements_text(_js))';

इसे SQL फ़ंक्शन करें , ताकि बड़े प्रश्नों में इनबिल्ट किया जा सके ।
इसे बनाएं IMMUTABLE(क्योंकि यह है) बड़े प्रश्नों में बार-बार मूल्यांकन से बचने के लिए और इसे इंडेक्स अभिव्यक्तियों में अनुमति दें।

कॉल करें:

SELECT tbl_id, json_arr2text_arr(data->'tags')
FROM   tbl;

db <> फिडल यहां


9.3 या उससे अधिक उम्र के पोस्टग्रेट्स

फ़ंक्शन का उपयोग करें json_array_elements()। लेकिन हमें इसमें से दोहरे उद्धरण दिए गए हैं।

बाहरी क्वेरी में एकत्रीकरण के साथ वैकल्पिक क्वेरी। CROSS JOINगायब या खाली सरणियों के साथ पंक्तियों को निकालता है। प्रसंस्करण तत्वों के लिए भी उपयोगी हो सकता है। हमें समग्र करने के लिए एक अद्वितीय कुंजी चाहिए:

SELECT t.tbl_id, string_agg(d.elem::text, ', ') AS list
FROM   tbl t
CROSS  JOIN LATERAL json_array_elements(t.data->'tags') AS d(elem)
GROUP  BY t.tbl_id;

ARRAY कंस्ट्रक्टर, अभी भी उद्धृत स्ट्रिंग्स के साथ:

SELECT tbl_id, ARRAY(SELECT json_array_elements(t.data->'tags')) AS quoted_txt_arr
FROM   tbl t;

ध्यान दें कि nullऊपर के विपरीत, पाठ मान "null" में परिवर्तित हो गया है। गलत, सख्ती से बोलना, और संभावित अस्पष्ट।

गरीब आदमी के साथ निर्विवाद trim():

SELECT t.tbl_id, string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM   tbl t, json_array_elements(t.data->'tags') d(elem)
GROUP  BY 1;

Tbl से एकल पंक्ति को पुनः प्राप्त करें:

SELECT string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM   tbl t, json_array_elements(t.data->'tags') d(elem)
WHERE  t.tbl_id = 1;

स्ट्रिंग्स फॉर्म सहसंबद्ध उपश्रेणी:

SELECT tbl_id, (SELECT string_agg(trim(value::text, '"'), ', ')
                FROM   json_array_elements(t.data->'tags')) AS list
FROM   tbl t;

ARRAY निर्माता:

SELECT tbl_id, ARRAY(SELECT trim(value::text, '"')
                     FROM   json_array_elements(t.data->'tags')) AS txt_arr
FROM   tbl t;

मूल (पुराना) SQL फिडेल
db <> फिडल यहां।

सम्बंधित:

नोट्स (पुराना 9.4 से पुराना)

हमें JSON सरणी से उचित मान वापस करने json_array_elements_text(json)के json_array_elements(json)लिए a , ट्विन की textआवश्यकता होगी। लेकिन यह JSON फ़ंक्शन प्रदान किए गए शस्त्रागार से गायब प्रतीत होता है । या textअदिश JSONमान से मान निकालने के लिए कुछ अन्य कार्य । मुझे लगता है कि एक भी याद आ रही है।
इसलिए मैंने इसके साथ सुधार किया trim(), लेकिन यह गैर-तुच्छ मामलों के लिए विफल हो जाएगा ...


हमेशा की तरह अच्छा पोस्ट, लेकिन आंतरिक के अपने ज्ञान के साथ क्यों नहीं सरणी-> jsonb से कास्ट है। मैं समझ सकता हूं कि अन्य कलाकारों को लागू नहीं किया जा सकता क्योंकि sql-array अधिक दृढ़ता से टाइप किया गया है। क्या यह सिर्फ इसलिए है क्योंकि PostgreSQL ऑटो जनरेट करने के कोड (int [], bigint [], टेक्स्ट []] इत्यादि के विपरीत है
इवान कैरोल

3
@ इवान: आप to_jsonb()सरणी-> जोंसब रूपांतरण के लिए उपयोग करेंगे।
इरविन ब्रान्डेसटेटर

क्या SELECT ARRAY(SELECT json_array_elements_text(_js))वास्तव में गारंटी देता है कि सरणी का क्रम संरक्षित है? क्या अनुकूलक को सैद्धांतिक रूप से json_array_elements_text से निकलने वाली पंक्तियों के क्रम को बदलने की अनुमति नहीं है?
फेलिक्स गिसेन्डॉफर

@ फेलिक्स: SQL मानक में कोई औपचारिक गारंटी नहीं है। (उसके बाद फिर से, मानक एसक्यूएल में सेलेक्ट लिस्ट में सेट रिटर्निंग फ़ंक्शंस की भी अनुमति नहीं है।) लेकिन पोस्टग्रैज मैनुअल में एक अनौपचारिक जोर है। देखें: dba.stackexchange.com/a/185862/3684 स्पष्ट करने के लिए - एक मामूली इत्र दंड की कीमत पर - देखें: dba.stackexchange.com/a/27287/3684 । व्यक्तिगत रूप से, मुझे विश्वास है कि यह विशेष अभिव्यक्ति है जो 9.4 के बाद के पोस्टग्रेज के हर वर्तमान और भविष्य के संस्करण में अपेक्षित रूप से काम करता है।
इरविन ब्रान्डस्टेट्टर

@ErwinBrandstetter इस बात की पुष्टि करने के लिए बहुत बहुत धन्यवाद! मैं वर्तमान में एक लेख के लिए कुछ शोध कर रहा हूं जो कि पोस्टग्रेक्यूएल द्वारा प्रदान की गई औपचारिक और अनौपचारिक गारंटियों की गारंटी देता है और आपके उत्तर अविश्वसनीय रूप से उपयोगी हैं! यदि आप लेख की समीक्षा करने में रुचि रखते हैं तो मुझे बताएं, लेकिन कोई चिंता नहीं। मैं आपके StackOverflow योगदान के लिए अविश्वसनीय रूप से आभारी हूँ और आपने वर्षों से बहुत कुछ सीखा है!
फेलिक्स गिसेन्डॉफर

16

पीजी 9.4+

स्वीकृत उत्तर निश्चित रूप से आपको क्या चाहिए, लेकिन यहाँ सादगी के लिए एक सहायक है जिसका मैं इसके लिए उपयोग करता हूं:

CREATE OR REPLACE FUNCTION jsonb_array_to_text_array(
  p_input jsonb
) RETURNS TEXT[] AS $BODY$

DECLARE v_output text[];

BEGIN

  SELECT array_agg(ary)::text[]
  INTO v_output
  FROM jsonb_array_elements_text(p_input) AS ary;

  RETURN v_output;

END;

$BODY$
LANGUAGE plpgsql VOLATILE;

तो बस करो:

SELECT jsonb_array_to_text_array('["a", "b", "c"]'::jsonb);

मैंने अपने उत्तर और सरल कार्य के लिए कुछ तेज अभिव्यक्तियाँ जोड़ीं। यह काफी सस्ता हो सकता है।
एरविन ब्रान्डसेट्टर

4
यह फ़ंक्शन शुद्ध SQL होना चाहिए ताकि ऑप्टिमाइज़र इसमें जा सके। यहां pgplsql का उपयोग करने की आवश्यकता नहीं है।
विभाजित करें

8

PostgreSQL मेलिंग सूचियों पर यह प्रश्न पूछा गया था और मैं JSON क्षेत्र निष्कर्षण ऑपरेटर के माध्यम से JSON पाठ को PostgreSQL पाठ प्रकार में परिवर्तित करने के इस हैकिंग तरीके के साथ आया था:

CREATE FUNCTION json_text(json) RETURNS text IMMUTABLE LANGUAGE sql
AS $$ SELECT ('['||$1||']')::json->>0 $$;

db=# select json_text(json_array_elements('["hello",1.3,"\u2603"]'));
 json_text 
-----------
 hello
 1.3
 

मूल रूप से यह मूल्य को एकल-तत्व सरणी में परिवर्तित करता है और फिर पहले तत्व के लिए पूछता है।

एक और तरीका यह होगा कि इस ऑपरेटर का उपयोग सभी क्षेत्रों को एक-एक करके निकालने के लिए किया जाएगा। लेकिन बड़े सरणियों के लिए यह धीमा है, क्योंकि इसमें प्रत्येक सरणी तत्व के लिए पूरे JSON स्ट्रिंग को पार्स करने की आवश्यकता होती है, जिससे O (n ^ 2) जटिलता होती है।

CREATE FUNCTION json_array_elements_text(json) RETURNS SETOF text IMMUTABLE LANGUAGE sql
AS $$ SELECT $1->>i FROM generate_series(0, json_array_length($1)-1) AS i $$;

db=# select json_array_elements_text('["hello",1.3,"\u2603"]');
 json_array_elements_text 
--------------------------
 hello
 1.3
 

1

मैंने कुछ विकल्पों का परीक्षण किया है। यहाँ मेरी पसंदीदा क्वेरी है। मान लें कि हमारे पास एक आईडी और json फ़ील्ड वाली तालिका है। Json फ़ील्ड में सरणी होती है, जिसे हम pg सरणी में बदलना चाहते हैं।

SELECT * 
FROM   test 
WHERE  TRANSLATE(jsonb::jsonb::text, '[]','{}')::INT[] 
       && ARRAY[1,2,3];

यह दूसरों की तुलना में कहीं भी और तेजी से काम कर रहा है, लेकिन बैसाखी दिखता है)

सबसे पहले json array टेक्स्ट के रूप में डाली जाती है, और फिर हम स्क्वायर ब्रैकेट को कोष्ठक में बदलते हैं। अंत में पाठ को आवश्यक प्रकार के सरणी के रूप में डाला जा रहा है।

SELECT TRANSLATE('[1]'::jsonb::text, '[]','{}')::INT[];

और यदि आप पाठ [] सरणियाँ पसंद करते हैं

SELECT TRANSLATE('[1]'::jsonb::text, '[]','{}')::TEXT[];

2
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"मुझे लगता है कि आपको कुछ स्पष्टीकरण जोड़ना होगा कि यह कैसे काम करना है।
dezso

सवाल यह है कि जेएसएन सरणी (!) को पीजी सरणी में कैसे बदलना है। मान लीजिए कि मेरे पास id और jsonb कॉलम वाली तालिका है। JSONb कॉलम में json array होती है। फिर
FiscalCliff

TRANSLATE (jsonb :: jsonb :: text, '[]', '{}') :: INT [] json array को pg ऐरे में कनवर्ट करता है।
FiscalCliff

SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"यह इतना बम-प्रूफ नहीं है ...
dezso

इन सरणियों के लिए पाठ [] का उपयोग करने पर विचार करें
FiscalCliff

0

इस प्रश्न के उत्तर से लिए गए ये कुछ कार्य हैं, जो मैं उपयोग कर रहा हूं और वे शानदार काम कर रहे हैं

CREATE OR REPLACE FUNCTION json_array_casttext(json) RETURNS text[] AS $f$
    SELECT array_agg(x) || ARRAY[]::text[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION jsonb_array_casttext(jsonb) RETURNS text[] AS $f$
    SELECT array_agg(x) || ARRAY[]::text[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION json_array_castint(json) RETURNS int[] AS $f$
    SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION jsonb_array_castint(jsonb) RETURNS int[] AS $f$
    SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

उनमें से प्रत्येक में, एक खाली सरणी के साथ सम्‍मिलित करके, वे एक ऐसे मामले को संभालते हैं, जिसने मुझे अपने दिमाग को थोड़ा-थोड़ा करने के लिए उकसाया था, यदि आप कोशिश करते हैं और खाली सरणी को json/ से jsonbकाटते हैं तो इसके बिना आपको कुछ नहीं मिलेगा, बजाय खाली सरणी ( {}) जैसा कि आप उम्मीद करेंगे। मुझे यकीन है कि उनके लिए कुछ अनुकूलन है, लेकिन वे इस अवधारणा को समझाने में सरलता के लिए शेष हैं।

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