Json_agg के अंदर कॉलम चुनें


21

मेरे पास एक प्रश्न है:

SELECT a.id, a.name, json_agg(b.*) as "item"
  FROM a
  JOIN b ON b.item_id = a.id
 GROUP BY a.id, a.name;

मैं कॉलम का चयन कैसे कर सकता हूं bताकि मेरे पास b.item_idJSON ऑब्जेक्ट में न हो ?

मैंने इसके बारे में पढ़ा है ROW, लेकिन यह JSON ऑब्जेक्ट देता है:

{"f1": "Foo", "f2": "Bar"}

एक बार उचित कॉलम कुंजियों से मेल खाने के लिए मुझे JSON ऑब्जेक्ट को रीमैप करने की आवश्यकता होगी। मैं उससे बचना चाहूंगा और मूल कॉलम नाम रखूंगा।

जवाबों:


50

दुर्भाग्य से, "इस एक कॉलम को छोड़कर सभी कॉलम" कहने के लिए SQL सिंटैक्स में कोई प्रावधान नहीं है । आप पंक्ति-प्रकार की अभिव्यक्ति में स्तंभों की शेष सूची को वर्तनी के द्वारा अपना लक्ष्य प्राप्त कर सकते हैं :

SELECT a.id, a.name
     , json_agg((b.col1, b.col2, b.col3)) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

यही कारण है कि अधिक स्पष्ट रूप के लिए कम है: । ROW(b.col1, b.col2, b.col3)

हालाँकि, कॉलम नाम पंक्ति-प्रकार के भावों में संरक्षित नहीं हैं। आपको इस तरह से JSON ऑब्जेक्ट में सामान्य कुंजी नाम मिलते हैं। मुझे मूल कॉलम नामों को संरक्षित करने के लिए 3 विकल्प दिखाई देते हैं:

1. पंजीकृत प्रकार के लिए डाली

एक प्रसिद्ध (पंजीकृत) पंक्ति प्रकार के लिए कास्ट करें। प्रत्येक मौजूदा तालिका या दृश्य के लिए या एक स्पष्ट CREATE TYPEविवरण के साथ एक प्रकार पंजीकृत है । आप एक तदर्थ समाधान (सत्र की अवधि के लिए जीवन) के लिए एक अस्थायी तालिका का उपयोग कर सकते हैं:

CREATE TEMP TABLE x (col1 int, col2 text, col3 date);  -- use adequate data types!

SELECT a.id, a.name
     , json_agg((b.col1, b.col2, b.col3)::x) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

2. एक सबसिलेक्ट का उपयोग करें

एक व्युत्पन्न तालिका के निर्माण के लिए एक उप-विषयक का उपयोग करें और तालिका को संपूर्ण रूप में संदर्भित करें । यह स्तंभ नाम भी रखता है। यह अधिक क्रिया है, लेकिन आपको एक पंजीकृत प्रकार की आवश्यकता नहीं है:

SELECT a.id, a.name
     , json_agg((SELECT x FROM (SELECT b.col1, b.col2, b.col3) AS x)) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

3. json_build_object()Postgres 9.4 या बाद में

SELECT a.id, a.name
     , json_agg(json_build_object('col1', b.col1, 'col2', b.col2, 'col3', b.col3)) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

सम्बंधित:

के लिए इसी तरह jsonbसंबंधित कार्यों के साथ jsonb_agg()और jsonb_build_object()

के लिए Postgres 9.5 या बाद में यह भी देखना a_horse का जवाब एक नया छोटा वाक्य रचना प्रकार के साथ: Postgres जोड़ा माइनस ऑपरेटर -के लिएjsonb कहने के लिए "यह एक कुंजी को छोड़ कर सभी चाबियाँ"
चूंकि Postgres 10 "कई कुंजियों को छोड़कर" एक ही ऑपरेटर के साथ कार्यान्वित किया जाता है जो text[]कि 2 ऑपरेंड के रूप में लिया जाता है - जैसे कि mlt टिप्पणी।


1
> या कई कुंजियाँ ध्यान दें कि json (b) -text [] 10. से शुरू हो रहा है
mlt

समाधान 3 ने मेरे लिए एक आकर्षण की तरह काम किया!
लुइज़ फर्नांडो दा सिल्वा

17

9.6 से शुरू होकर आप -JSONB से कुंजी निकालने के लिए उपयोग कर सकते हैं :

SELECT a.id, a.name, jsonb_agg(to_jsonb(b) - 'item_id') as "item"
FROM a
  JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;

to_jsonb(b)पूरी पंक्ति को रूपांतरित कर - 'item_id'देगा और फिर कुंजी को उस नाम item_idसे हटा देगा जिसका परिणाम तब एकत्र किया गया है।


यह नई सुविधाएँ प्रतीत होती हैं कि ओपी क्या उम्मीद कर रहा था। मैंने अपने उत्तर के लिए एक लिंक जोड़ा।
इरविन ब्रान्डेसटेटर

जब मैंने सबसिनेट वैरिएंट की कोशिश की, तो मुझे json_aggफंक्शन से संबंधित एक त्रुटि मिली :function json_agg(record) does not exist
fraxture

@fraxture: तब आप पोस्टग्रेज 9.6 का उपयोग नहीं कर रहे हैं
a_horse_with_no_name

वास्तव में यही समस्या थी। क्या v9.2 में स्तंभों को फ़िल्टर करने का कोई तरीका है?
फ्रैक्चर

8

आप वास्तव में उप-समूहों का उपयोग करके समूह के बिना कर सकते हैं

SELECT 
  a.id, a.name, 
  ( 
    SELECT json_agg(item)
    FROM (
      SELECT b.c1 AS x, b.c2 AS y 
      FROM b WHERE b.item_id = a.id
    ) item
  ) AS items
FROM a;

रिटर्न

{
  id: 1,
  name: "thing one",
  items:[
    { x: "child1", y: "child1 col2"},
    { x: "child2", y: "child2 col2"}
  ]
}

जॉन एटन का यह लेख वास्तव में दिलचस्प है और इसमें अधिक विवरण हैं


2

मैंने पाया है कि JSON बनाने के लिए यह सबसे अच्छा है, फिर इसे एग्रीगेट करें। जैसे

with base as (
select a, b, ('{"ecks":"' || to_json(x) || '","wai":"' || to_json(y) || '","zee":"' || to_json(z) || '"}"')::json c
) select (a, b, array_to_json(array_agg(c)) as c)

ध्यान दें कि यदि आप सीटीई पसंद नहीं करते हैं (या इसका उपयोग करने के कारण प्रदर्शन की समस्याएं हैं) तो इसे एक उपश्रेणी के रूप में किया जा सकता है।

ध्यान दें, यदि आप ऐसा करने जा रहे हैं, तो आपके लिए कुंजी-मूल्य जोड़े को लपेटने के लिए फ़ंक्शन बनाने के लिए फायदेमंद हो सकता है ताकि कोड साफ दिखे। आप अपना फ़ंक्शन (उदाहरण के लिए) पास करेंगे 'ecks', 'x'और यह वापस आ जाएगा "ecks": "x"


1

हालांकि अभी भी सभी कॉलमों के चयन के बारे में कुछ भी करने का कोई तरीका नहीं है, लेकिन आप json_agg(to_json(b.col_1, b.col_2, b.col_3 ...))प्रारूप में प्रत्येक jsons के एक json सरणी प्राप्त करने के लिए उपयोग कर सकते हैं {"col_1":"col_1 value", ...}

तो क्वेरी कुछ इस तरह दिखाई देगी:

SELECT a.id, a.name, json_agg(to_json(b.col_1,b.col_2,b.col_3...)) as item
  FROM a
  JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;

और पंक्तियों को इस रूप में लौटाएगा:

id, name, item
8, the_name, [{"col_1":"value_1","col_2":"value_2","col_3":"value_3"...}, {"col_1":"value_1.2","col_2":"value_2.2","col_3":"value_3.2"...},...]
9, the_next_name, [{"col_1":"value_1.3","col_2":"value_2.3","col_3":"value_3.3"...},   {"col_1":"value_1.4","col_2":"value_2.4","col_3":"value_3.4"...},...]
...

(जब यह समर्थन जोड़ा गया था तो मैं अभी 9.5.3 पोस्टग्रेज पर हूं और 100% निश्चित नहीं हूं।)


1

आप json_build_objectइस तरह का उपयोग कर सकते हैं

SELECT 
  a.id, 
  a.name,
  json_agg(json_build_object('col1', b.col1, 'col2', b.col2) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.