উপাদান সংখ্যা সহ পোস্টগ্রাইএসকিউএল অজানা ()


90

আমার যখন পৃথক মান সহ একটি কলাম থাকবে তখন আমি unnest()ফাংশনটি ব্যবহার করতে পারি :

myTable
id | elements
---+------------
1  |ab,cd,efg,hi
2  |jk,lm,no,pq
3  |rstuv,wxyz

select id, unnest(string_to_array(elements, ',')) AS elem
from myTable

id | elem
---+-----
1  | ab
1  | cd
1  | efg
1  | hi
2  | jk
...

আমি কীভাবে উপাদান সংখ্যা অন্তর্ভুক্ত করতে পারি? অর্থাৎ:

id | elem | nr
---+------+---
1  | ab   | 1
1  | cd   | 2
1  | efg  | 3
1  | hi   | 4
2  | jk   | 1
...

আমি উত্স স্ট্রিংয়ের প্রতিটি উপাদানটির মূল অবস্থানটি চাই । আমি জানালা ফাংশন (সঙ্গে চেষ্টা করেছি row_number(), rank()ইত্যাদি) কিন্তু আমি সবসময় পেতে 1। কারণ তারা উত্স টেবিলের একই সারিতে আছেন?

আমি জানি এটি একটি খারাপ টেবিল ডিজাইন। এটি আমার নয়, আমি এটি ঠিক করার চেষ্টা করছি।

উত্তর:


184

9.4 বা তার পরে পোস্টগ্রেস করে

WITH ORDINALITYসেট-রিটার্নিং ফাংশনগুলির জন্য ব্যবহার করুন :

FROMধারাটিতে কোনও ফাংশন যখন প্রত্যয়িত হয় WITH ORDINALITY, তখন একটি bigintকলাম আউটপুটে যুক্ত হয় যা 1 থেকে শুরু হয় এবং ফাংশনের আউটপুটটির প্রতিটি সারিটির জন্য 1 দ্বারা বৃদ্ধি হয়। সেট রিটার্নিং ফাংশনগুলির ক্ষেত্রে এটি সবচেয়ে কার্যকর unnest()

LATERALপৃষ্ঠা 9.3+-এ বৈশিষ্ট্যটির সাথে এবং পিএএসএসকিএল-হ্যাকারগুলির এই থ্রেড অনুসারে , উপরের প্রশ্নটি এখন এইভাবে লেখা যেতে পারে:

SELECT t.id, a.elem, a.nr
FROM   tbl AS t
LEFT   JOIN LATERAL unnest(string_to_array(t.elements, ','))
                    WITH ORDINALITY AS a(elem, nr) ON TRUE;

LEFT JOIN ... ON TRUEবাম টেবিলের সমস্ত সারি সংরক্ষণ করে, ডানদিকে টেবিলের অভিব্যক্তিটি যদি কোনও সারি দেয় না। যদি এটি উদ্বেগের বিষয় না হয় তবে আপনি এটি অন্যথায় সমতুল্য ব্যবহার করতে পারেন, কম ভার্বোস ফর্মটি অন্তর্ভুক্ত সহCROSS JOIN LATERAL :

SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr);

অথবা সরল যদি ভিত্তি করে থাকে একটি সত্যিকারের অ্যারের সরানো হয় ( arrঅ্যারে কলাম হচ্ছে):

SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr);

বা এমনকি, ন্যূনতম সিনট্যাক্স সহ:

SELECT id, a, ordinality
FROM   tbl, unnest(arr) WITH ORDINALITY a;

a স্বয়ংক্রিয়ভাবে টেবিল হয় এবং কলামের নাম। যুক্ত অরডিনালিটি কলামের ডিফল্ট নাম ordinality। তবে সুস্পষ্ট কলামের নাম এবং টেবিল-যোগ্য কোলাম যুক্ত করা ভাল (নিরাপদ, ক্লিনার)।

পোস্টগ্রিজ 8.4 - 9.3

সঙ্গে row_number() OVER (PARTITION BY id ORDER BY elem)আপনি সাজানোর ক্রম অনুসারে সংখ্যাগুলি পাওয়ার স্ট্রিংয়ের মূল অর্ডিনাল অবস্থানের অর্ডিনাল সংখ্যাটি নয় ।

আপনি কেবল বাদ দিতে পারেন ORDER BY :

SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM  (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t;

যদিও এটি সাধারণত কার্যকর হয় এবং আমি কখনও কখনও এটি সাধারণ প্রশ্নে ব্যর্থ হতে দেখিনি, পোস্টগ্রেএসকিউএল ছাড়াই সারিগুলির ক্রম সম্পর্কিত কিছুই জোর করে না ORDER BY। এটি বাস্তবায়নের বিশদের কারণে কাজ করে।

করতে পূরণবাচক সংখ্যা গ্যারান্টি ফাঁকা বিভাজিত উপাদানের স্ট্রিং :

SELECT id, arr[nr] AS elem, nr
FROM  (
   SELECT *, generate_subscripts(arr, 1) AS nr
   FROM  (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t
   ) sub;

বা সরল যদি সত্যিকারের অ্যারের ভিত্তিতে থাকে :

SELECT id, arr[nr] AS elem, nr
FROM  (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t;

ডিবিএএসই সম্পর্কিত সম্পর্কিত উত্তর:

পোস্টগ্রিজ 8.1 - 8.4

এই বৈশিষ্ট্যগুলির কোনটি এখনো পাওয়া যায়,: RETURNS TABLE, generate_subscripts(), unnest(), array_length()। তবে এটি কাজ করে:

CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer)
  RETURNS SETOF record
  LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1
 FROM   generate_series(array_lower($1,1), array_upper($1,1)) i';

বিশেষত দ্রষ্টব্য, অ্যারে সূচক উপাদানগুলির মূল অবস্থান থেকে পৃথক হতে পারে। একটি বর্ধিত ফাংশন সহ এই ডেমোটি বিবেচনা করুন :

CREATE FUNCTION f_unnest_ord_idx(anyarray, OUT val anyelement, OUT ordinality int, OUT idx int)
  RETURNS SETOF record
  LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1, i
 FROM   generate_series(array_lower($1,1), array_upper($1,1)) i';

SELECT id, arr, (rec).*
FROM  (
   SELECT *, f_unnest_ord_idx(arr) AS rec
   FROM  (VALUES (1, '{a,b,c}'::text[])  --  short for: '[1:3]={a,b,c}'
               , (2, '[5:7]={a,b,c}')
               , (3, '[-9:-7]={a,b,c}')
      ) t(id, arr)
   ) sub;

 id |       arr       | val | ordinality | idx
----+-----------------+-----+------------+-----
  1 | {a,b,c}         | a   |          1 |   1
  1 | {a,b,c}         | b   |          2 |   2
  1 | {a,b,c}         | c   |          3 |   3
  2 | [5:7]={a,b,c}   | a   |          1 |   5
  2 | [5:7]={a,b,c}   | b   |          2 |   6
  2 | [5:7]={a,b,c}   | c   |          3 |   7
  3 | [-9:-7]={a,b,c} | a   |          1 |  -9
  3 | [-9:-7]={a,b,c} | b   |          2 |  -8
  3 | [-9:-7]={a,b,c} | c   |          3 |  -7

তুলনা করা:


10
পোস্টগ্র্রেএসকিউএল সম্পর্কিত এই উত্তরটি এসও-এর সর্বাধিক বিস্তৃত উত্তর। ধন্যবাদ ইরভিন
আলেকজান্দ্রোস

আমরা কি নতুন পৃষ্ঠার সংস্করণগুলিতে নীচে আনইস্ট 2 ফাংশনটিকে একটি বাস্তব টেবিল রিটার্নে (জাল সারি নয়) রূপান্তর করতে পারি ?
পিটার ক্রাউস

@ ইরউইন-ব্র্যান্ডসেট্টার, আপনি দয়া করে কেন / যদি WITH ORDINALITYতার চেয়ে বেশি পছন্দ করেন তবে এই বিষয়ে বিস্তারিত বলবেন generate_subscripts()? এটি আমার কাছে দেখতে generate_subscripts()আরও ভাল যেমন এটি অ্যারেতে আসল উপাদান অবস্থানটি দেখায়। এটি দরকারী, উদাহরণস্বরূপ, অ্যারে আপডেট করার সময় ... আমি WITH ORDINALITYপরিবর্তে ব্যবহার করা উচিত ?
হারিয়ে গেছে

4
@ লস্টহর্স: আমি এটির মতো রূপরেখা জানাব: এসকিউএল কোয়েরিতে কোনও সেট রিটার্নিং ফাংশনের WITH ORDINALITYজন্য সারি নম্বর পাওয়ার সাধারণ সমাধান is এটি দ্রুততম, নির্ভরযোগ্য উপায় এবং এটি 1-ডাইমেনশনাল, 1-ভিত্তিক অ্যারে (পোস্টগ্র্যাস অ্যারেগুলির জন্য ডিফল্ট, এটি বিবেচনা করুন ) জন্য পুরোপুরি কাজ করার জন্যও ঘটে । আপনি যদি অন্য কোনও ধরণের অ্যারে নিয়ে কাজ করেন (বেশিরভাগ লোকেরা করেন না) এবং আপনাকে প্রকৃত সাবস্ক্রিপ্টগুলির সাথে সংরক্ষণ / কাজ করার প্রয়োজন হয়, তবে যাওয়ার উপায়। তবে এটিকে শুরু করার জন্য অলসভাবে চ্যাপ্টা করে ...generate_subscripts()unnest()
এরউইন ব্র্যান্ডসেটেটার

4
@ z0r_ ম্যানুয়াল: Table functions appearing in FROM can also be preceded by the key word LATERAL, but for functions the key word is optional; the function's arguments can contain references to columns provided by preceding FROM items in any case.
এরউইন ব্র্যান্ডসটেটার

9

চেষ্টা করুন:

select v.*, row_number() over (partition by id order by elem) rn from
(select
    id,
    unnest(string_to_array(elements, ',')) AS elem
 from myTable) v

6

সাবস্ক্রিপ্ট উত্পাদক কার্যাদি ব্যবহার করুন ।
http://www.postgresql.org/docs/current/static/function-srf.html#FUNCTIONS-SRF-SUBScriptTS

উদাহরণ স্বরূপ:

SELECT 
  id
  , elements[i] AS elem
  , i AS nr
FROM
  ( SELECT 
      id
      , elements
      , generate_subscripts(elements, 1) AS i
    FROM
      ( SELECT
          id
          , string_to_array(elements, ',') AS elements
        FROM
          myTable
      ) AS foo
  ) bar
;

আরও সহজভাবে:

SELECT
  id
  , unnest(elements) AS elem
  , generate_subscripts(elements, 1) AS nr
FROM
  ( SELECT
      id
      , string_to_array(elements, ',') AS elements
    FROM
      myTable
  ) AS foo
;

3

যদি উপাদান ক্রম গুরুত্বপূর্ণ না হয়, আপনি পারেন

select 
  id, elem, row_number() over (partition by id) as nr
from (
  select
      id,
      unnest(string_to_array(elements, ',')) AS elem
  from myTable
) a

0

unnest2() অনুশীলন হিসাবে

Pg v8.4 এর আগের পুরানো সংস্করণগুলির জন্য ব্যবহারকারী সংজ্ঞায়িত হওয়া দরকার unnest()। আমরা এই পুরাতন ফাংশনটিকে একটি সূচক সহ উপাদানগুলি ফিরিয়ে আনতে পারি:

CREATE FUNCTION unnest2(anyarray)
  RETURNS setof record  AS
$BODY$
  SELECT $1[i], i
  FROM   generate_series(array_lower($1,1),
                         array_upper($1,1)) i;
$BODY$ LANGUAGE sql IMMUTABLE;

4
এটি pg v8.4 এর আগে কাজ করবে না, কারণ RETURNS TABLEএখনও নেই। সমাধান সম্পর্কে আলোচনা করে আমি আমার উত্তরে একটি অধ্যায় যুক্ত করেছি।
এরউইন ব্র্যান্ডস্টেটার

4
@ এরউইন ব্র্যান্ডসটেটার, আপনার উত্তরগুলি খুব প্রাসঙ্গিক, এবং আপনি 4 বছর আগে (!) এর একটি পাঠ্য পালিশ করছেন ... আপনি কি নিজের এসও পাঠ্য ব্যবহার করে পোস্টগ্রিসকিউএল বই লিখছেন? :-)
পিটার ক্রাউস

হাই সব, এটি উইকি, আপনি সম্পাদনা করতে পারেন (!) ... তবে ঠিক আছে, আমি সংশোধন করেছি setof record
পিটার ক্রাউস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.