পোস্টগ্রিএসকিউএল 9.2 সারি_তে_জসন () নেস্টেড যোগ দিয়ে যোগ দেয়


85

row_to_json()পোস্টগ্র্রেএসকিউএল 9.2-এ যুক্ত করা ফাংশনটি ব্যবহার করে আমি জেএসএনে একটি প্রশ্নের ফলাফল ম্যাপ করার চেষ্টা করছি ।

জড়িত সারিগুলিকে নেস্টেড অবজেক্টস হিসাবে উপস্থাপনের সর্বোত্তম উপায় বের করতে আমার সমস্যা হচ্ছে (1: 1 সম্পর্ক)

এখানে আমি চেষ্টা করেছি (সেটআপ কোড: সারণী, স্যাম্পল ডেটা, ক্যোয়ারির পরে):

-- some test tables to start out with:
create table role_duties (
    id serial primary key,
    name varchar
);

create table user_roles (
    id serial primary key,
    name varchar,
    description varchar,
    duty_id int, foreign key (duty_id) references role_duties(id)
);

create table users (
    id serial primary key,
    name varchar,
    email varchar,
    user_role_id int, foreign key (user_role_id) references user_roles(id)
);

DO $$
DECLARE duty_id int;
DECLARE role_id int;
begin
insert into role_duties (name) values ('Script Execution') returning id into duty_id;
insert into user_roles (name, description, duty_id) values ('admin', 'Administrative duties in the system', duty_id) returning id into role_id;
insert into users (name, email, user_role_id) values ('Dan', 'someemail@gmail.com', role_id);
END$$;

ক্যোয়ারী নিজেই:

select row_to_json(row)
from (
    select u.*, ROW(ur.*::user_roles, ROW(d.*::role_duties)) as user_role 
    from users u
    inner join user_roles ur on ur.id = u.user_role_id
    inner join role_duties d on d.id = ur.duty_id
) row;

আমি যদি ব্যবহার করতাম তবে আমি ROW()ফলাফলগুলি ক্ষেত্রগুলিকে একটি শিশু সামগ্রীতে আলাদা করতে পারতাম, তবে এটি একক স্তরের মধ্যে সীমাবদ্ধ বলে মনে হয়। আমি আরও AS XXXবিবৃতি সন্নিবেশ করতে পারি না , যেমনটি আমি মনে করি এই ক্ষেত্রে আমার প্রয়োজন হওয়া উচিত।

আমি কলামের নাম বহন করেছি, কারণ আমি যথাযথ রেকর্ড টাইপ করেছি, উদাহরণস্বরূপ ::user_roles, সেই টেবিলের ফলাফলের ক্ষেত্রে।

এখানে যে প্রশ্নটি ফিরে আসে তা এখানে:

{
   "id":1,
   "name":"Dan",
   "email":"someemail@gmail.com",
   "user_role_id":1,
   "user_role":{
      "f1":{
         "id":1,
         "name":"admin",
         "description":"Administrative duties in the system",
         "duty_id":1
      },
      "f2":{
         "f1":{
            "id":1,
            "name":"Script Execution"
         }
      }
   }
}

আমি যা করতে চাই তা হল যুক্ত হওয়ার জন্য জেএসএন উত্পন্ন করা (আবার 1: 1 ভাল আছে) যেখানে আমি যোগ দিতে পারি এবং তাদের সাথে যুক্ত হওয়া পিতামাতার চাইল্ড অবজেক্ট হিসাবে তাদের প্রতিনিধিত্ব করে, যেমন নীচের মত:

{
   "id":1,
   "name":"Dan",
   "email":"someemail@gmail.com",
   "user_role_id":1,
   "user_role":{
         "id":1,
         "name":"admin",
         "description":"Administrative duties in the system",
         "duty_id":1
         "duty":{
            "id":1,
            "name":"Script Execution"
         }
      }
   }
}

কোন সাহায্য প্রশংসা করা হয়। পড়ার জন্য ধন্যবাদ.


4
এটি সেটআপ কোডে আছে। সন্নিবেশগুলি। আমি সবকিছু সেট আপ করার সমস্যায় পড়েছিলাম যাতে যে কেউ আমার পরিস্থিতির প্রতিরূপ তৈরি করতে পারে।
ডোয়ারার

উত্তর:


164

আপডেট করুন: ইন পোস্টগ্রি 9.4 এই অনেক উন্নত প্রবর্তনের সঙ্গে to_json, json_build_object, json_objectএবংjson_build_array , যদিও এটা সব ক্ষেত্র স্পষ্টভাবে নাম প্রয়োজন কারণে বাগাড়ম্বরপূর্ণ আছে:

select
        json_build_object(
                'id', u.id,
                'name', u.name,
                'email', u.email,
                'user_role_id', u.user_role_id,
                'user_role', json_build_object(
                        'id', ur.id,
                        'name', ur.name,
                        'description', ur.description,
                        'duty_id', ur.duty_id,
                        'duty', json_build_object(
                                'id', d.id,
                                'name', d.name
                        )
                )
    )
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;

পুরানো সংস্করণগুলির জন্য, পড়ুন।


এটি একক সারিতে সীমাবদ্ধ নয়, এটি কেবল খানিকটা বেদনাদায়ক। আপনি ব্যবহার করে যৌগিক সারি টাইপগুলি ব্যবহার করতে পারবেন না AS, সুতরাং প্রভাব অর্জনের জন্য আপনার একটি এলিয়াসড সাবকোয়ারি এক্সপ্রেশন বা সিটিই ব্যবহার করতে হবে:

select row_to_json(row)
from (
    select u.*, urd AS user_role
    from users u
    inner join (
        select ur.*, d
        from user_roles ur
        inner join role_duties d on d.id = ur.duty_id
    ) urd(id,name,description,duty_id,duty) on urd.id = u.user_role_id
) row;

http : //json ব্যাখ্যাtyprint.com/ এর মাধ্যমে উত্পাদন করে :

{
  "id": 1,
  "name": "Dan",
  "email": "someemail@gmail.com",
  "user_role_id": 1,
  "user_role": {
    "id": 1,
    "name": "admin",
    "description": "Administrative duties in the system",
    "duty_id": 1,
    "duty": {
      "id": 1,
      "name": "Script Execution"
    }
  }
}

আপনি array_to_json(array_agg(...))যখন 1 ব্যবহার করবেন তখন আপনি ব্যবহার করতে চাইবেন : অনেকগুলি সম্পর্ক, বিটিডাব্লু।

উপরের ক্যোয়ারীটি আদর্শভাবে লিখতে সক্ষম হবে:

select row_to_json(
    ROW(u.*, ROW(ur.*, d AS duty) AS user_role)
)
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;

... তবে পোস্টগ্রিসএসকিউএল এর ROWকনস্ট্রাক্টর ASকলামের উপনাম গ্রহণ করে না । দুঃখজনকভাবে

ধন্যবাদ, তারা একই অপটিমাইজ। পরিকল্পনাগুলি তুলনা করুন:

কারণ সিটিইগুলি অপ্টিমাইজেশন বেড়া, শৃঙ্খলযুক্ত সিটিই ( WITHএক্সপ্রেশন) ব্যবহার করার জন্য নেস্টেড সাবকোয়ারি সংস্করণটিকে পুনরায় প্রেরণ করতে পারে না এবং এটি একই পরিকল্পনার ফলস্বরূপ ফল পাবে না। row_to_jsonএক্ষেত্রে আপনি কিছুটা কুৎসিত নেস্টেড সাবকিউরিয়েন্সের সাথে আটকে রয়েছেন যতক্ষণ না আমরা কোনও ROWনির্মাণকারীর কলামের নামগুলিকে আরও সরাসরিভাবে ওভাররাইড করার উপায় পেয়ে যাই get


যাইহোক, সাধারণভাবে, নীতিটি হ'ল যেখানে আপনি কলামগুলি দিয়ে একটি জসন অবজেক্ট তৈরি করতে চান a, b, cএবং আপনি চান যে আপনি কেবল অবৈধ বাক্য গঠন লিখতে পারেন:

ROW(a, b, c) AS outername(name1, name2, name3)

আপনি পরিবর্তে সারি-টাইপ করা মানগুলিতে ফিরে আসা স্কেলার সাবকিউরি ব্যবহার করতে পারেন:

(SELECT x FROM (SELECT a AS name1, b AS name2, c AS name3) x) AS outername

বা:

(SELECT x FROM (SELECT a, b, c) AS x(name1, name2, name3)) AS outername

অতিরিক্ত হিসাবে, মনে রাখবেন যে jsonঅতিরিক্ত উদ্ধৃতি ব্যতীত আপনি মানগুলি রচনা করতে পারেন , উদাহরণস্বরূপ যদি আপনি একটিটির আউটপুটটি একটি এর json_aggমধ্যে রেখে দেন row_to_jsonতবে অভ্যন্তরীণ json_aggফলাফলটি স্ট্রিং হিসাবে উদ্ধৃত হবে না, এটি সরাসরি জসন হিসাবে অন্তর্ভুক্ত হবে।

যেমন স্বেচ্ছাচারী উদাহরণে:

SELECT row_to_json(
        (SELECT x FROM (SELECT
                1 AS k1,
                2 AS k2,
                (SELECT json_agg( (SELECT x FROM (SELECT 1 AS a, 2 AS b) x) )
                 FROM generate_series(1,2) ) AS k3
        ) x),
        true
);

আউটপুটটি হ'ল:

{"k1":1,
 "k2":2,
 "k3":[{"a":1,"b":2}, 
 {"a":1,"b":2}]}

নোট করুন যে json_aggপণ্যটি [{"a":1,"b":2}, {"a":1,"b":2}], যেমনটি textহবে , তেমনি পুনরায় পালানো হয়নি ।

এর অর্থ আপনি সারি তৈরির জন্য জসন অপারেশনগুলি রচনা করতে পারবেন , আপনাকে সর্বদা বিশাল জটিল পোস্টগ্রেএসকিউএল যৌগিক প্রকার তৈরি করতে হবে না তারপরে row_to_jsonআউটপুট কল করতে হবে।


4
আমি যদি আপনার উত্তরটি আরও দু'বার উচ্চারণ করতে পারি তবে আমি চাই। আমি বিস্তারিত এবং 1: এর অনেকটা সম্পর্কে প্রশংসা করি।
ডোয়ারার

7
@ দার্নার খুশি একটি ভাল প্রশ্ন লেখার প্রচেষ্টা করার জন্য ধন্যবাদ; আমি এটিকে আরও কয়েকবার ধাবিত করতে চাই । নমুনা তথ্য, পিজি সংস্করণ, প্রত্যাশিত আউটপুট, প্রকৃত আউটপুট / ত্রুটি; সমস্ত বাক্সে টিক দেয়, এবং এটি পরিষ্কার এবং বুঝতে সহজ। সূতরাং ধন্যবাদ.
ক্রেগ রিঞ্জার

4
@ মাইস্টোশোর্ট: প্রকারটি সরবরাহ করার জন্য একটি টেম্প টেবিলটিও পরিবেশন করে এবং স্বয়ংক্রিয়ভাবে মুছে ফেলা হয় সেশনটির শেষে।
এরউইন ব্র্যান্ডস্টেটার

4
9.4 উদাহরণের জন্য আপনাকে অনেক ধন্যবাদ। json_build_objectআমার জীবনকে আরও সহজ করে তুলতে চলেছে তবে আমি যখন প্রকাশের নোটগুলি দেখলাম তখন কোনওভাবেই আমি এটি গ্রহণ করিনি। কখনও কখনও আপনাকে শুরু করার জন্য একটি দৃ a় উদাহরণ প্রয়োজন need
জেফ

4
সুপার উত্তর - সম্মত হন যে ডকুমেন্টেশনটি json_build_objectআরও কিছুটা হাইলাইট করা উচিত - এটি আসল গেম চেঞ্জার।
ববমার্কি

2

আমি এই সমাধানটি যুক্ত করছি কারণ গ্রহণযোগ্য প্রতিক্রিয়া N: N টি সম্পর্ককে বিবেচনা করে না as ওরফে: অবজেক্টের সংগ্রহের সংগ্রহ

আপনার যদি N: N এর সাথে সম্পর্ক থাকে তবে withএটি আপনার বন্ধু us আমার উদাহরণে, আমি নীচের শ্রেণিবিন্যাসের একটি গাছের ভিউ তৈরি করতে চাই।

A Requirement - Has - TestSuites
A Test Suite - Contains - TestCases.

নিম্নলিখিত কোয়েরি যোগদান করে প্রতিনিধিত্ব করে।

SELECT reqId ,r.description as reqDesc ,array_agg(s.id)
            s.id as suiteId , s."Name"  as suiteName,
            tc.id as tcId , tc."Title"  as testCaseTitle

from "Requirement" r 
inner join "Has"  h on r.id = h.requirementid 
inner join "TestSuite" s on s.id  = h.testsuiteid
inner join "Contains" c on c.testsuiteid  = s.id 
inner join "TestCase"  tc on tc.id = c.testcaseid
  GROUP BY r.id, s.id;

যেহেতু আপনি একাধিক সংঘবদ্ধতা করতে পারবেন না তাই আপনার "WITH" ব্যবহার করা দরকার।

with testcases as (
select  c.testsuiteid,ts."Name" , tc.id, tc."Title"  from "TestSuite" ts
inner join "Contains" c on c.testsuiteid  = ts.id 
inner join "TestCase"  tc on tc.id = c.testcaseid

),                
requirements as (
    select r.id as reqId ,r.description as reqDesc , s.id as suiteId
    from "Requirement" r 
    inner join "Has"  h on r.id = h.requirementid 
    inner join "TestSuite" s on s.id  = h.testsuiteid

    ) 
, suitesJson as (
 select  testcases.testsuiteid,  
       json_agg(
                json_build_object('tc_id', testcases.id,'tc_title', testcases."Title" )
            ) as suiteJson
    from testcases 
    group by testcases.testsuiteid,testcases."Name"
 ),
allSuites as (
    select has.requirementid,
           json_agg(
                json_build_object('ts_id', suitesJson.testsuiteid,'name',s."Name"  , 'test_cases', suitesJson.suiteJson )
            ) as suites
            from suitesJson inner join "TestSuite" s on s.id  = suitesJson.testsuiteid
            inner join "Has" has on has.testsuiteid  = s.id
            group by has.requirementid
),
allRequirements as (
    select json_agg(
            json_build_object('req_id', r.id ,'req_description',r.description , 'test_suites', allSuites.suites )
            ) as suites
            from allSuites inner join "Requirement" r on r.id  = allSuites.requirementid

)
 select * from allRequirements

এটি যা করে তা হ'ল JSON অবজেক্টকে ছোট ছোট আইটেমের সংগ্রহ এবং প্রতিটি withক্লিউজুলগুলিতে তাদের একত্রিত করা ।

ফলাফল:

[
  {
    "req_id": 1,
    "req_description": "<character varying>",
    "test_suites": [
      {
        "ts_id": 1,
        "name": "TestSuite",
        "test_cases": [
          {
            "tc_id": 1,
            "tc_title": "TestCase"
          },
          {
            "tc_id": 2,
            "tc_title": "TestCase2"
          }
        ]
      },
      {
        "ts_id": 2,
        "name": "TestSuite",
        "test_cases": [
          {
            "tc_id": 2,
            "tc_title": "TestCase2"
          }
        ]
      }
    ]
  },
  {
    "req_id": 2,
    "req_description": "<character varying> 2 ",
    "test_suites": [
      {
        "ts_id": 2,
        "name": "TestSuite",
        "test_cases": [
          {
            "tc_id": 2,
            "tc_title": "TestCase2"
          }
        ]
      }
    ]
  }
]

1

দীর্ঘমেয়াদে রক্ষণাবেক্ষণের জন্য আমার পরামর্শটি হ'ল আপনার ক্যোয়ারির মোটা সংস্করণটি তৈরি করতে একটি ভিউইউ ব্যবহার করুন এবং তারপরে নীচের মত একটি ফাংশন ব্যবহার করুন:

CREATE OR REPLACE FUNCTION fnc_query_prominence_users( )
RETURNS json AS $$
DECLARE
    d_result            json;
BEGIN
    SELECT      ARRAY_TO_JSON(
                    ARRAY_AGG(
                        ROW_TO_JSON(
                            CAST(ROW(users.*) AS prominence.users)
                        )
                    )
                )
        INTO    d_result
        FROM    prominence.users;
    RETURN d_result;
END; $$
LANGUAGE plpgsql
SECURITY INVOKER;

এই ক্ষেত্রে, অবজেক্ট prominence.users একটি দর্শন। যেহেতু আমি ব্যবহারকারীর বাছাই করেছি user

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