পোস্টগ্রিসএসকিউএল ক্রোস্টাব কোয়েরি


196

কেউ কি পোস্টগ্রেএসকিউএল-এ ক্রসস্ট্যাব ক্যোয়ারী তৈরি করতে জানেন?
উদাহরণস্বরূপ আমার কাছে নিম্নলিখিত সারণি রয়েছে:

Section    Status    Count
A          Active    1
A          Inactive  2
B          Active    4
B          Inactive  5

আমি কোয়েরিটি নিম্নলিখিত ক্রসস্ট্যাবটি ফিরে আসতে চাই:

Section    Active    Inactive
A          1         2
B          4         5

এটা কি সম্ভব?


1
আমার কিছুটা আলাদা কাঠামো ছিল এবং এই উদাহরণটি বোঝার জন্য আমি কিছুটা কঠিন পেয়েছি তাই আমি এই স্ট্যাকওভারফ্লো . com/q/49051959/808723 সম্পর্কে আমার চিন্তাভাবনার নথিটি নথিভুক্ত করেছি । এটি কারও পক্ষে সহায়ক।
গেমস্ক্রিপ্টিং

উত্তর:


317

ইনস্টল করুন অতিরিক্ত মডিউল tablefunc একবার প্রতি ডাটাবেস, যা ফাংশন প্রদান করে crosstab()। পোস্টগ্রাগেস 9.1 যেহেতু আপনি এটির CREATE EXTENSIONজন্য ব্যবহার করতে পারেন :

CREATE EXTENSION IF NOT EXISTS tablefunc;

উন্নত পরীক্ষার কেস

CREATE TABLE tbl (
   section   text
 , status    text
 , ct        integer  -- "count" is a reserved word in standard SQL
);

INSERT INTO tbl VALUES 
  ('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
                    , ('C', 'Inactive', 7);  -- ('C', 'Active') is missing

সাধারণ ফর্ম - অনুপস্থিত বৈশিষ্ট্যের জন্য উপযুক্ত নয়

crosstab(text)সঙ্গে 1 ইনপুট পরামিতি:

SELECT *
FROM   crosstab(
   'SELECT section, status, ct
    FROM   tbl
    ORDER  BY 1,2'  -- needs to be "ORDER BY 1,2" here
   ) AS ct ("Section" text, "Active" int, "Inactive" int);

রিটার্নস:

বিভাগ | সক্রিয় | নিষ্ক্রিয়
--------- + + -------- + + ----------
 ক | 1 | 2
 খ | 4 | 5
 সি |      7 | - !!
  • কাস্টিং এবং নতুন নামকরণের দরকার নেই।
  • এর জন্য ভুল ফলাফলটি নোট করুন C: মানটি 7প্রথম কলামে পূরণ করা হয়েছে। কখনও কখনও, এই আচরণটি কাঙ্ক্ষিত, তবে এই ব্যবহারের ক্ষেত্রে নয়।
  • সহজ ফর্মটি সরবরাহিত ইনপুট ক্যোয়ারিতে ঠিক তিনটি কলামেও সীমাবদ্ধ : সারি_নাম , বিভাগ , মান । নীচে 2-প্যারামিটার বিকল্পের মতো অতিরিক্ত কলামগুলির জন্য কোনও স্থান নেই।

নিরাপদ ফর্ম

crosstab(text, text)সঙ্গে 2 ইনপুট প্যারামিটার:

SELECT *
FROM   crosstab(
   'SELECT section, status, ct
    FROM   tbl
    ORDER  BY 1,2'  -- could also just be "ORDER BY 1" here

  , $$VALUES ('Active'::text), ('Inactive')$$
   ) AS ct ("Section" text, "Active" int, "Inactive" int);

রিটার্নস:

বিভাগ | সক্রিয় | নিষ্ক্রিয়
--------- + + -------- + + ----------
 ক | 1 | 2
 খ | 4 | 5
 সি | |        7   - !!
  • জন্য সঠিক ফলাফল নোট করুন C

  • দ্বিতীয় প্যারামিটারটি যে আয় এক কোন প্রশ্নের সাথে হতে পারে সারি অ্যাট্রিবিউট প্রতি শেষে কলাম সংজ্ঞা ক্রম মিলে। প্রায়শই আপনি অন্তর্নিহিত টেবিল থেকে আলাদা আলাদা বৈশিষ্ট্যগুলি এর মতো জিজ্ঞাসা করতে চাইবেন:

    'SELECT DISTINCT attribute FROM tbl ORDER BY 1'

    ম্যানুয়ালটিতে।

    যেহেতু আপনাকে যে কোনও উপায়ে কলাম সংজ্ঞা তালিকার সমস্ত কলামগুলি বানান করতে হয়েছে (প্রাক-সংজ্ঞায়িত রূপগুলি ব্যতীত ), সাধারণত এটি প্রকাশের মতো সংক্ষেপে একটি সংক্ষিপ্ত তালিকা সরবরাহ করা আরও দক্ষ :crosstabN()VALUES

    $$VALUES ('Active'::text), ('Inactive')$$)

    অথবা (ম্যানুয়ালটিতে নেই):

    $$SELECT unnest('{Active,Inactive}'::text[])$$  -- short syntax for long lists
  • উদ্ধৃতি সহজ করার জন্য আমি ডলার কোটিং ব্যবহার করেছি ।

  • আপনি এমনকি আউটপুট কলাম বিভিন্ন ধরনের তথ্য দিয়ে crosstab(text, text)- যতদিন মান কলামের টেক্সট উপস্থাপনা লক্ষ্য টাইপ জন্য বৈধ ইনপুট হয়। এই ভাবে আপনি থাকতে পারে বিভিন্ন ধরনের এবং আউটপুট গুণাবলীর text, date, numericনিজ নিজ বৈশিষ্ট্য জন্য ইত্যাদি। ম্যানুয়ালটিতে অধ্যায়টিরcrosstab(text, text) শেষে একটি কোড উদাহরণ রয়েছে ।

ডিবি <> ফিডল এখানে

উন্নত উদাহরণ


\crosstabview পিএসএইচএল-তে

পোস্টগ্রিস 9.6 এই মেটা-কমান্ডটিকে তার ডিফল্ট ইন্টারেক্টিভ টার্মিনাল পিএসএকিএল-তে যুক্ত করেছে । আপনি প্রথম crosstab()প্যারামিটার হিসাবে যে ক্যোয়ারীটি চালাতে পারেন তা চালিয়ে দিতে এবং এটিকে \crosstabview(তাত্ক্ষণিকভাবে বা পরবর্তী পদক্ষেপে) ফিড করতে পারেন । ভালো লেগেছে:

db=> SELECT section, status, ct FROM tbl \crosstabview

উপরের মতো অনুরূপ ফলাফল, তবে এটি ক্লায়েন্টের পক্ষে একচেটিয়াভাবে উপস্থাপনের বৈশিষ্ট্য । ইনপুট সারিগুলি কিছুটা আলাদাভাবে চিকিত্সা করা হয়, তাই ORDER BYএটি প্রয়োজন হয় না। \crosstabviewম্যানুয়ালটিতে বিশদ পৃষ্ঠার নীচে আরও কোড উদাহরণ রয়েছে।

ড্যানিয়েল ভেরিট (পিএসকিএল বৈশিষ্ট্যের লেখক) দ্বারা ডিবিএএসই সম্পর্কিত সম্পর্কিত উত্তর:



পূর্বে গৃহীত উত্তর পুরানো হয়েছে।

  • ফাংশনের রূপটি crosstab(text, integer)পুরানো। দ্বিতীয় integerপ্যারামিটার উপেক্ষা করা হয়। আমি বর্তমান ম্যানুয়ালটি উদ্ধৃত করছি :

    crosstab(text sql, int N) ...

    অপ্রচলিত সংস্করণ crosstab(text)। প্যারামিটারটি Nএখন উপেক্ষা করা হয়েছে, যেহেতু মান কলামগুলির সংখ্যা সর্বদা কলিং কোয়েরি দ্বারা নির্ধারিত হয়

  • অকারণে ingালাই এবং নতুন নামকরণ।

  • কোনও সারিতে সমস্ত বৈশিষ্ট্য না থাকলে এটি ব্যর্থ হয়। অনুপস্থিত বৈশিষ্ট্যগুলি সঠিকভাবে পরিচালনা করতে উপরের দুটি ইনপুট প্যারামিটার সহ নিরাপদ বৈকল্পিক দেখুন।

  • ORDER BYএক-প্যারামিটার আকারে প্রয়োজন বোধ করা হয় crosstab()ম্যানুয়াল:

    অনুশীলনে এসকিউএল কোয়েরি সর্বদা নির্দিষ্ট ORDER BY 1,2করে ইনপুট সারিগুলি যথাযথভাবে অর্ডার করা হয়েছে তা নিশ্চিত করতে হবে


3
+1, ভাল লেখার জন্য, লক্ষ্য করার জন্য ধন্যবাদIn practice the SQL query should always specify ORDER BY 1,2 to ensure that the input rows are properly ordered
ক্রিস্টোফেড

আমি $$ VALUES .. using ব্যবহার করে কিছু সমস্যা করেছি $$ আমি পরিবর্তে 'ভ্যালু (' '<<<>' ':: :: <টাইপ>), .. ব্যবহার করেছি'
মার্কো ফ্যান্টাসিয়া

আমরা কি ক্রসস্ট্যাব ক্যোয়ারীতে প্যারামিটার বাইন্ডিং নির্দিষ্ট করতে পারি? আমি এই ত্রুটিটি পেয়ে যাচ্ছি => type 2 প্যারামিটারের ধরণের ডেটা ধরণ নির্ধারণ করতে পারিনি
আশীষ

1
ক্রসস্ট্যাব ক্যোয়ারিতে কলামের জন্য ডিফল্ট মান সেট করা সম্ভব?
আশীষ

2
@ আশিষ: দয়া করে একটি নতুন প্রশ্ন শুরু করুন। মন্তব্য জায়গা নয়। আপনি প্রসঙ্গের জন্য সর্বদা এটির সাথে লিঙ্ক করতে পারেন।
এরউইন ব্র্যান্ডস্টেটর

30

আপনি অতিরিক্ত মডিউল টেবিলফঙ্কেরcrosstab() ফাংশনটি ব্যবহার করতে পারেন - যা আপনাকে ডাটাবেস প্রতি একবার ইনস্টল করতে হবে । PostgreSQL 9.1 যেহেতু আপনি এর জন্য ব্যবহার করতে পারেন :CREATE EXTENSION

CREATE EXTENSION tablefunc;

আপনার ক্ষেত্রে, আমি বিশ্বাস করি এটি এরকম কিছু দেখাচ্ছে:

CREATE TABLE t (Section CHAR(1), Status VARCHAR(10), Count integer);

INSERT INTO t VALUES ('A', 'Active',   1);
INSERT INTO t VALUES ('A', 'Inactive', 2);
INSERT INTO t VALUES ('B', 'Active',   4);
INSERT INTO t VALUES ('B', 'Inactive', 5);

SELECT row_name AS Section,
       category_1::integer AS Active,
       category_2::integer AS Inactive
FROM crosstab('select section::text, status, count::text from t',2)
            AS ct (row_name text, category_1 text, category_2 text);

যদি আপনি ক্রসস্ট্যাব ক্যোয়ারিতে কোনও প্যারামিটার ব্যবহার করেন তবে আপনাকে এটি সঠিকভাবে এড়িয়ে যেতে হবে। উদাহরণ: (উপরে থেকে) বলুন যে আপনি কেবল সক্রিয়গুলি চান: নির্বাচন করুন ... ক্রসস্ট্যাব থেকে নির্বাচন করুন ('বিভাগটি নির্বাচন করুন: পাঠ্য, স্থিতি, গণনা :: টি থেকে পাঠ্য যেখানে স্থিতি =' 'সক্রিয়' '', 2) এএস। .. (ডাবল উদ্ধৃতি লক্ষ্য করুন)। ব্যবহারকারীর দ্বারা রানটাইমগুলিতে প্যারামিটারটি পাস করার ক্ষেত্রে (উদাহরণস্বরূপ একটি ফাংশন প্যারামিটার হিসাবে) আপনি বলতে পারেন: নির্বাচন করুন ... ক্রসস্ট্যাব থেকে ('বিভাগটি নির্বাচন করুন: পাঠ্য, স্থিতি, গণনা :: টি থেকে টেক্সট যেখানে পরিস্থিতি =' ' '|| par_active ||' '' ', 2) এএস ... (এখানে ট্রিপল কোট!)। বিআরটি-তেও এটির সাথে কাজ করে? প্লেসহোল্ডার।
উইম ভারহ্যাভার্ট

26
SELECT section,
       SUM(CASE status WHEN 'Active' THEN count ELSE 0 END) AS active, --here you pivot each status value as a separate column explicitly
       SUM(CASE status WHEN 'Inactive' THEN count ELSE 0 END) AS inactive --here you pivot each status  value as a separate column explicitly

FROM t
GROUP BY section

1
টেবিলফঙ্ক মডিউলে ক্রসস্ট্যাব ক্রিয়াকলাপটি এই উত্তরটিতে কী যুক্ত করে, তা কি কেউ ব্যাখ্যা করতে পারেন যা হাতের কাজ উভয়ই করে, এবং আমার মনের কাছে বোঝা সহজ?
জন পাওয়েল

4
@ জনবারিয়া: এর মতো একটি সাধারণ কেস সহজেই CASE এর বিবৃতি দিয়ে সমাধান করা যেতে পারে। তবে এটি কেবল পূর্ণসংখ্যার চেয়ে আরও বেশি গুণাবলী এবং / অথবা অন্যান্য ডেটা ধরণের সাথে খুব তাড়াতাড়ি অযৌক্তিক হয়। একটি সরাইয়া হিসাবে: এই ফর্ম সমষ্টিগত ফাংশন ব্যবহার sum(), এটি ব্যবহার করার জন্য ভাল হবে min()বা max()কোন ELSE, যার জন্য কাজ করে textএছাড়াও। তবে এর তুলনায় সূক্ষ্মভাবে পৃথক প্রভাব রয়েছে corosstab(), যা প্রতি বৈশিষ্ট্যের জন্য শুধুমাত্র "প্রথম" মান ব্যবহার করে। যতক্ষণ না কেবল এক হতে পারে ততক্ষণ তা বিবেচনা করে না। পরিশেষে, কর্মক্ষমতাও প্রাসঙ্গিক। crosstab()সিতে লেখা এবং কাজের জন্য অনুকূলিত।
এরউইন ব্র্যান্ডস্টেটার

এটি আমার জন্য পোস্টগ্রিস্কল-এর জন্য কাজ করে না। আমি ত্রুটিটি পেয়েছিERROR: 42803: aggregate function calls may not be nested
অড্রে

1
@ অড্রে আপনি কি একই এসকিউএল চালাচ্ছেন না?

2
কোডের একটি ব্লক বনাম ব্যাখ্যা যোগ করার বিষয়ে বিবেচনা করুন
ড্যানিয়েল এল। ভ্যানডেনবোশ

10

JSON সমষ্টি সহ সমাধান:

CREATE TEMP TABLE t (
  section   text
, status    text
, ct        integer  -- don't use "count" as column name.
);

INSERT INTO t VALUES 
  ('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
                   , ('C', 'Inactive', 7); 


SELECT section,
       (obj ->> 'Active')::int AS active,
       (obj ->> 'Inactive')::int AS inactive
FROM (SELECT section, json_object_agg(status,ct) AS obj
      FROM t
      GROUP BY section
     )X

আপনাকে ধন্যবাদ, এটি একটি সম্পর্কিত সমস্যার সাথে আমাকে সহায়তা করেছে।
জেফচার্টার

1

দুঃখিত এটি সম্পূর্ণ হয়নি কারণ আমি এখানে এটি পরীক্ষা করতে পারছি না, তবে এটি আপনাকে সঠিক দিকে নামিয়ে দিতে পারে। আমি আমার ব্যবহার করা কিছু থেকে অনুবাদ করছি যা অনুরূপ কোয়েরি করে:

select mt.section, mt1.count as Active, mt2.count as Inactive
from mytable mt
left join (select section, count from mytable where status='Active')mt1
on mt.section = mt1.section
left join (select section, count from mytable where status='Inactive')mt2
on mt.section = mt2.section
group by mt.section,
         mt1.count,
         mt2.count
order by mt.section asc;

আমি যে কোড থেকে কাজ করছি তা হ'ল:

select m.typeID, m1.highBid, m2.lowAsk, m1.highBid - m2.lowAsk as diff, 100*(m1.highBid - m2.lowAsk)/m2.lowAsk as diffPercent
from mktTrades m
   left join (select typeID,MAX(price) as highBid from mktTrades where bid=1 group by typeID)m1
   on m.typeID = m1.typeID
   left join (select typeID,MIN(price) as lowAsk  from mktTrades where bid=0 group by typeID)m2
   on m1.typeID = m2.typeID
group by m.typeID, 
         m1.highBid, 
         m2.lowAsk
order by diffPercent desc;

যা কোনও টাইপআইডি ফিরিয়ে দেবে, সর্বাধিক দামের বিড এবং সর্বনিম্ন মূল্য জিজ্ঞাসা করা হয়েছে এবং দুটির মধ্যে পার্থক্য (ইতিবাচক পার্থক্যের অর্থ এমন কোনও কিছু কেনা যাবে যা বিক্রি হতে পারে তার চেয়ে কম দামে))


1
আপনি একটি ধারা থেকে মিস করছেন, অন্যথায় এটি সঠিক। ব্যাখ্যার পরিকল্পনাগুলি আমার সিস্টেমে বুনোভাবে আলাদা - ক্রসস্ট্যাব ফাংশনটির ব্যয় 22.5 এবং বাম জয়েন্টের পদ্ধতির প্রায় 91 গুণ ব্যয়বহুল প্রায় 91 গুণ ব্যয় হয়। এটি প্রায় দু'বার শারীরিক পাঠ এবং হ্যাশ যোগদানের দ্বিগুণ সম্পাদন করে - যা অন্যান্য যোগদানের ধরণের তুলনায় বেশ ব্যয়বহুল হতে পারে।
জেরেমিয়া পেশকা

ধন্যবাদ যিরমিয়, এটি জানা ভাল। আমি অন্য উত্তরটি আপগ্রেটেড করেছি, তবে আপনার মন্তব্যটি মূল্যবান তাই আমি এটিকে মুছব না।
ল্যান্সএইচ

-1

Crosstabtablefuncএক্সটেনশনের অধীনে ফাংশন উপলব্ধ । ডাটাবেসের জন্য আপনাকে এই এক্সটেনশনটি একবার তৈরি করতে হবে।

এক্সটেনশন তৈরি করুন tablefunc;

ক্রস ট্যাব ব্যবহার করে পিভট টেবিল তৈরি করতে আপনি নীচের কোডটি ব্যবহার করতে পারেন:

create table test_Crosstab( section text,
<br/>status text,
<br/>count numeric)

<br/>insert into test_Crosstab values ( 'A','Active',1)
                <br/>,( 'A','Inactive',2)
                <br/>,( 'B','Active',4)
                <br/>,( 'B','Inactive',5)

select * from crosstab(
<br/>'select section
    <br/>,status
    <br/>,count
    <br/>from test_crosstab'
    <br/>)as ctab ("Section" text,"Active" numeric,"Inactive" numeric)

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