sql - कम पंक्तियों के साथ एक पंक्ति को कई पंक्तियों में कनवर्ट करें




postgresql unpivot lateral (4)

SELECT
  times.name, x.t, x.val
FROM
  times cross join lateral (values('st',st),('ot',ot),('dt',dt)) as x(t,val)
WHERE
  x.val <> 0;

मैं PostgreSQL में एकल पंक्तियों में एकाधिक पंक्तियों में परिवर्तित करना चाहता हूं, जहां कुछ कॉलम निकाल दिए जाते हैं वर्तमान आउटपुट का एक उदाहरण यहां दिया गया है:

name | st | ot | dt |
-----|----|----|----|
Fred | 8  | 2  | 3  |
Jane | 8  | 1  | 0  |
Samm | 8  | 0  | 6  |  
Alex | 8  | 0  | 0  |  

निम्नलिखित क्वेरी का उपयोग करना:

SELECT
   name, st, ot, dt
FROM
   times;

और यहां मैं क्या चाहता हूं:

name |  t | val |
-----|----|-----|
Fred | st |  8  |
Fred | ot |  2  |
Fred | dt |  3  |
Jane | st |  8  |
Jane | ot |  1  |
Samm | st |  8  |
Samm | dt |  6  |
Alex | st |  8  |

उपरोक्त वांछित आउटपुट पाने के लिए मैं क्वेरी को कैसे संशोधित कर सकता हूं?


मुख्य समस्या एक धुरी / क्रॉसस्टैब ऑपरेशन के पीछे है। कभी-कभी "अनपिवॉट" कहा जाता है

असल में, एबेलिस्टो की क्वेरी पोस्टग्रेज़ 9.3 या उसके बाद के संस्करण में जाने का तरीका है। सम्बंधित:

आप परिणाम में मान्य मानों के बिना नाम शामिल करने के लिए LEFT JOIN LATERAL ... ON u.val <> 0 इस्तेमाल करना चाह सकते हैं (और सिंटैक्स को थोड़ा छोटा कर सकते हैं)

यदि आपके पास कुछ मूल्य कॉलम (या कॉलम की अलग-अलग सूची) से अधिक है, तो आप क्वेरी को स्वचालित रूप से बनाने और निष्पादित करने के लिए फ़ंक्शन का उपयोग करना चाह सकते हैं:

CREATE OR REPLACE FUNCTION f_unpivot_columns(VARIADIC _cols text[])
  RETURNS TABLE(name text, t text, val int) AS
$func$
BEGIN
   RETURN QUERY EXECUTE (
   SELECT
     'SELECT t.name, u.t, u.val
      FROM   times t
      LEFT   JOIN LATERAL (VALUES '
          || string_agg(format('(%L, t.%I)', c, c), ', ')
          || ') u(t, val) ON (u.val <> 0)'
   FROM   unnest(_cols) c
   );
END
$func$  LANGUAGE plpgsql;

कॉल करें:

SELECT * FROM f_unpivot_times_columns(VARIADIC '{st, ot, dt}');

या:

SELECT * FROM f_unpivot_columns('ot', 'dt');

कॉलम के नामों को स्ट्रिंग लीटरल के रूप में प्रदान किया जाता है और कोई भी अतिरिक्त दो-उद्धरण चिह्नों के साथ सही (केस-संवेदनशील!) स्पेलिंग होना चाहिए देख:

dbfiddle यहाँ

अधिक उदाहरण और स्पष्टीकरण के साथ संबंधित:


एक रास्ता:

with times(name , st , ot , dt) as(
select 'Fred',8  , 2  , 3  union all
select 'Jane',8  , 1  , 0  union all
select 'Samm',8  , 0  , 6  union all
select 'Alex',8  , 0  , 0  
)

select name, key as t, value::int  from 
(
    select name, json_build_object('st' ,st , 'ot',ot, 'dt',dt) as j
    from times
) t
join lateral json_each_text(j)
on true
where value <> '0'
-- order by name, case when key = 'st' then 0 when key = 'ot' then 1 when key = 'dt' then 2 end

यदि नेस्टेड हैश मानचित्र या सरणी बनाई जा सकती हैं, तो मैं बस शुरुआत से तालिका नीचे जा सकता हूं और प्रत्येक आइटम को नेस्टेड सरणी में जोड़ सकता हूं। मुझे पता लगाने के लिए नेस्टेड सरणी में कौन सा स्तर डालने के लिए प्रत्येक पंक्ति को रूट नोड पर ट्रेस करना होगा। मैं ज्ञापन को नियोजित कर सकता हूं ताकि मुझे एक ही माता-पिता को बार-बार देखने की आवश्यकता न हो।

संपादित करें: मैं पूरी तालिका को पहले सरणी में पढ़ूंगा, इसलिए यह बार-बार डीबी से पूछताछ नहीं करेगा। बेशक यह आपकी व्यावहारिक नहीं होगी यदि आपकी तालिका बहुत बड़ी है।

संरचना के निर्माण के बाद, मुझे इसके माध्यम से पहली बार गहराई से करना होगा और HTML को प्रिंट करना होगा।

एक टेबल का उपयोग करके इस जानकारी को स्टोर करने के लिए कोई बेहतर मौलिक तरीका नहीं है (हालांकि मैं गलत हो सकता हूं;), और बेहतर समाधान देखना अच्छा लगेगा)। हालांकि, यदि आप गतिशील रूप से निर्मित डीबी टेबल को नियोजित करने के लिए एक योजना बनाते हैं, तो आपने सादगी के बलिदान और एसक्यूएल नरक का जोखिम; पर एक पूरी नई दुनिया खोला;)।





sql postgresql unpivot lateral