পোস্ট কোয়েস্ট্রিএলে মাস এবং বছর অনুসারে গ্রুপ কোয়েরি ফলাফল


156

পোস্টগ্রিস সার্ভারে আমার নিম্নলিখিত ডাটাবেস টেবিলটি রয়েছে:

id      date          Product Sales
1245    01/04/2013    Toys    1000     
1245    01/04/2013    Toys    2000
1231    01/02/2013    Bicycle 50000
456461  01/01/2014    Bananas 4546

আমি একটি কোয়েরি তৈরি করতে চাই SUMযা Salesকলামটি দেয় এবং ফলাফলগুলি মাস এবং বছর অনুসারে গ্রুপ করে:

Apr    2013    3000     Toys
Feb    2013    50000    Bicycle
Jan    2014    4546     Bananas

এটি করার কোনও সহজ উপায় আছে?

উত্তর:


217
select to_char(date,'Mon') as mon,
       extract(year from date) as yyyy,
       sum("Sales") as "Sales"
from yourtable
group by 1,2

রাদুর অনুরোধে, আমি সেই প্রশ্নের ব্যাখ্যা করব:

to_char(date,'Mon') as mon, : "তারিখ" গুণকে মাসের সংক্ষিপ্ত রূপের সংজ্ঞায়িত ফর্ম্যাটে রূপান্তর করে।

extract(year from date) as yyyy : পোস্টগ্রাএসকিএলএর "এক্সট্রাক্ট" ফাংশনটি YYYY বছরকে "তারিখ" বৈশিষ্ট্য থেকে নিষ্কাশন করতে ব্যবহৃত হয়।

sum("Sales") as "Sales" : এসইউএম () ফাংশনটি সমস্ত "বিক্রয়" মান যুক্ত করে এবং ডাবল-কোট ব্যবহার করে কেস সংবেদনশীলতা সহ একটি কেস-সংবেদনশীল উপন্যাস সরবরাহ করে।

group by 1,2: গ্রুপ বাই ফাংশনে অবশ্যই SELECT তালিকা থেকে সমস্ত কলাম থাকতে হবে যা সমষ্টিগুলির অংশ নয় (ওরফে, সমস্ত কলামগুলি SUM / AVG / MIN / MAX ইত্যাদির অভ্যন্তরে নয়)) এটি ক্যোয়ারিকে বলছে যে কলামগুলির প্রতিটি অনন্য সংমিশ্রণের জন্য এসইউএম () প্রয়োগ করা উচিত, যা এক্ষেত্রে মাস এবং বছরের কলাম। "1,2" অংশটি কলামের নাম ব্যবহার করার পরিবর্তে একটি শর্টহ্যান্ড, যদিও পঠনযোগ্যতার জন্য পুরো "টু_চর (...)" এবং "নিষ্কাশন (...)" এক্সপ্রেশনটি ব্যবহার করা ভাল।


5
আমি ব্যাখ্যা না দিয়ে উত্তর না দেওয়া খুব ভাল ধারণা বলে মনে করি না, বিশেষত নতুনদের জন্য। আপনার উত্তরের পিছনে যুক্তিটি ব্যাখ্যা করা উচিত ছিল, সম্ভবত কিছুটা হলেও (যদিও এটি আমাদের বাকীগুলির জন্য সহজ এবং সরল মনে হতে পারে)।
রাদু ঘিওরঘিউ

1
@ বুড়াকআরস্লান ফলাফলগুলি কি দেখতে যেমন ওপি বিশেষত অনুরোধ করেছিল?
বিএম

2
@ আরগারডপ্যাক, আউটপুটটি date_truncঠিক প্রশ্নকর্তা যা চান তা নয়: select date_trunc('month', timestamp '2001-02-16 20:38:40')::date=>2001-02-01
পিসারুক

2
আমি ব্যবহার ধারণা পছন্দ date_truncমধ্যে group byদফা।
পিসারুক

1
সম্ভাব্য "ক্ষেত্র অবশ্যই দলে বিভাগে" গ্রুপে থাকতে হবে ... ওভার (পার্টিশন বাই) ব্যবহার করা ভাল।
জোন

317

আমি বিশ্বাস করতে পারি না গৃহীত উত্তরের এতগুলি উত্স রয়েছে - এটি একটি ভয়ঙ্কর পদ্ধতি।

ডেট_ট্রুঙ্ক সহ এটি করার সঠিক উপায় এখানে :

   SELECT date_trunc('month', txn_date) AS txn_month, sum(amount) as monthly_sum
     FROM yourtable
 GROUP BY txn_month

এটি খারাপ অনুশীলন তবে আপনি যদি ব্যবহার করেন তবে আপনাকে ক্ষমা করা যেতে পারে

 GROUP BY 1

খুব সাধারণ প্রশ্নে।

আপনি ব্যবহার করতে পারেন

 GROUP BY date_trunc('month', txn_date)

আপনি যদি তারিখটি নির্বাচন করতে না চান


6
দুর্ভাগ্যক্রমে আউটপুটটি date_truncপ্রশ্নকর্তা প্রত্যাশা করেনি: select date_trunc('month', timestamp '2001-02-16 20:38:40')=> 2001-02-01 00:00:00
পিসারুক

4
আমি সম্মত যে এই পদ্ধতিটি আরও ভাল। আমি নিশ্চিত নই তবে আমি মনে করি এটি আরও কার্যকর, কারণ দু'জনের পরিবর্তে একটি করে গ্রুপিং রয়েছে। আপনার যদি সেই তারিখটি পুনরায় ফর্ম্যাট করার প্রয়োজন হয় তবে পরে আপনি অন্যান্য to_char(date_trunc('month', txn_date), 'YY-Mon')
উত্তরে

1
হ্যাঁ, স্বীকৃত উত্তরের জন্য ভোটের সংখ্যা হ'ল মাইন্ড বগল। date_truncএই সঠিক উদ্দেশ্যে তৈরি করা হয়েছিল। দুটি কলাম তৈরি করার কোনও কারণ নেই
অ্যালেনওলি

2
খুব সুন্দর! এটি একটি উচ্চতর উত্তর, বিশেষত যেহেতু আপনি পাশাপাশি অর্ডারও করতে পারেন। সম্মত!
ববমার্কি

1
তবুও আরেকটি উদাহরণ যেখানে সর্বাধিক আপত্তিজনক উত্তরটি গ্রহণযোগ্য উত্তরের সামনে উপস্থিত হওয়া উচিত
ব্রায়ান রিস্ক

33

to_char আসলে আপনাকে এক বছরের মধ্যে মাস এবং মাস বের করতে দেয়!

select to_char(date('2014-05-10'),'Mon-YY') as year_month; --'May-14'
select to_char(date('2014-05-10'),'YYYY-MM') as year_month; --'2014-05'

বা উপরের ব্যবহারকারীর উদাহরণের ক্ষেত্রে:

select to_char(date,'YY-Mon') as year_month
       sum("Sales") as "Sales"
from some_table
group by 1;

6
আপনার টেবিলে যদি কোনও শালীন পরিমাণের ডেটা থাকে তবে আমি এটি করার বিরুদ্ধে দৃ strongly়ভাবে পরামর্শ দেব। এই সঞ্চালিত অনেক চেয়ে খারাপ date_truncপদ্ধতি যখন দ্বারা গ্রুপ অনুষ্ঠানে যোগ দেন। আমার হাতে একটি ডিবি পরীক্ষামূলক, 270 কে সারি সহ একটি টেবিলে, তারিখ_আরঙ্ক পদ্ধতি TO_CHAR এর গতির দ্বিগুণ হয়ে গেছে
ক্রিস ক্লার্ক

@ ক্রিসকার্ক যদি পারফরম্যান্স উদ্বেগজনক হয় তবে আমি সম্মত হই যে ডেট_ট্রুঙ্ক ব্যবহার করা বোধগম্য হতে পারে তবে কিছু ক্ষেত্রে ফরম্যাটযুক্ত তারিখের স্ট্রিং থাকা ভাল, । উদাহরণস্বরূপ, আপনি যদি রেডশিফ্ট ব্যবহার করে একটি দ্রুত বিশ্লেষণ রিপোর্ট চালাচ্ছেন এবং এটি সাধারণত 3 সেকেন্ড সময় নেয় তবে 6 সেকেন্ডের ক্যোয়ারী সম্ভবত ঠিক আছে (যদিও, আপনি যদি প্রতিবেদনগুলি চালাচ্ছেন তবে অতিরিক্ত গণনা একটি ছোট শতাংশ দ্বারা জিনিসকে ধীর করে ফেলবে, কারণ একটি বৃহত গণনামূলক ওভারহেড রয়েছে)
মিগলডওয়াসার

1
আপনি এখনও এটি করতে পারেন - কোয়েরি অনুসারে গ্রুপটিকে 'মোড়ানো' দিয়ে আলাদা পদক্ষেপ হিসাবে ফর্ম্যাটটি করুন। উদাহরণস্বরূপ to_char (d, 'YYYY-DD') FROM থেকে নির্বাচন করুন (তারিখ_আরঙ্ক নির্বাচন করুন ('মাস', d) AS "d" থেকে tbl) AS foo। দুই ভুবনের সেরা!
ক্রিস ক্লার্ক

1
এই সমাধানটি সহজ এবং মার্জিত। আমি এটি পছন্দ করি এবং আমার ক্ষেত্রে এটি যথেষ্ট দ্রুত। এই উত্তরের জন্য আপনাকে ধন্যবাদ!
গেটলি

5

পোস্টগ্রিসে ডেট_ পার্ট () ফাংশনটি ব্যবহার করে ফলাফল অর্জনের অন্য উপায় রয়েছে।

 SELECT date_part('month', txn_date) AS txn_month, date_part('year', txn_date) AS txn_year, sum(amount) as monthly_sum
     FROM yourtable
 GROUP BY date_part('month', txn_date)

ধন্যবাদ


1

বিএমএ উত্তরটি দুর্দান্ত! আমি এটি অ্যাক্টিভেকর্ডসের সাহায্যে ব্যবহার করেছি, এখানে কারও কারও কাছে এর দরকার পড়লে এটি এখানে:

Model.find_by_sql(
  "SELECT TO_CHAR(created_at, 'Mon') AS month,
   EXTRACT(year from created_at) as year,
   SUM(desired_value) as desired_value
   FROM desired_table
   GROUP BY 1,2
   ORDER BY 1,2"
)

3
বা আপনি এটি করতে পারেন yourscopeorclass.group("extract(year from tablename.colname)")এবং একসাথে বছর, মাস, দিন পাওয়ার জন্য 3 বার শৃঙ্খলা করতে পারেন
nruth

1

এই টিউটোরিয়ালের উদাহরণ E দেখুন -> https://www.postgresqltutorial.com/postgresql-group-by/

নির্বাচনের মাধ্যমে আপনি তৈরি ভার্চুয়াল অ্যাট্রিবিটির নাম কল না করে আপনাকে নিজের গ্রুপে ফাংশনটি কল করতে হবে। আমি উপরের সমস্ত উত্তরগুলির প্রস্তাবিত যা করছিলাম তা আমি করছিলাম gettingcolumn 'year_month' does not exist ত্রুটি ।

আমার জন্য যা কাজ করেছিল তা হ'ল:

SELECT 
    date_trunc('month', created_at), 'MM/YYYY' AS month
FROM 
    "orders"  
GROUP BY 
    date_trunc('month', created_at)

0

পোস্টগ্রিসের কয়েকটি ধরণের টাইমস্ট্যাম্প রয়েছে:

টাইমজোন ছাড়াই টাইমস্ট্যাম্প - (ইউটিসি টাইমস্ট্যাম্পগুলি সংরক্ষণ করা ভাল) আপনি এটি বহুজাতিক ডাটাবেস স্টোরেজে খুঁজে পাবেন। এক্ষেত্রে ক্লায়েন্ট প্রতিটি দেশের জন্য টাইমজোন অফসেটের যত্ন নেবে।

টাইমজোন সহ টাইমস্ট্যাম্প - টাইমস্টোন অফসেট ইতিমধ্যে টাইমস্ট্যাম্পের অন্তর্ভুক্ত।

কিছু ক্ষেত্রে, আপনার ডাটাবেস সময় অঞ্চল ব্যবহার করে না তবে আপনার এখনও স্থানীয় সময় অঞ্চল এবং দিবালোক সংরক্ষণের সময় বিবেচনা করে রেকর্ডগুলি গ্রুপ করতে হবে (যেমন https://www.timeanddate.com/time/zone/romania/bucharest )

টাইমজোন যুক্ত করতে আপনি এই উদাহরণটি ব্যবহার করতে পারেন এবং আপনার সাথে অফসেট টাইমজোনটি প্রতিস্থাপন করতে পারেন।

"your_date_column" at time zone '+03'

ডিএসটি নির্দিষ্ট করে +1 গ্রীষ্মকালীন সময়ের অফসেট যুক্ত করতে আপনার টাইমস্ট্যাম্প গ্রীষ্মের ডিএসটিতে পড়ে কিনা তা পরীক্ষা করে দেখতে হবে। যেহেতু এই অন্তরগুলি 1 বা 2 দিনের সাথে পরিবর্তিত হয়, তাই আমি এমন একটি এপ্রোক্সিমেশন ব্যবহার করব যা মাসের রেকর্ডগুলির শেষের উপর প্রভাব ফেলবে না, তাই এই ক্ষেত্রে আমি প্রতি বছর সঠিক বিরতি উপেক্ষা করতে পারি।

যদি আরও সুনির্দিষ্ট ক্যোয়ারী তৈরি করতে হয়, তবে আপনাকে আরও কেসগুলি তৈরি করতে শর্ত যুক্ত করতে হবে। তবে মোটামুটিভাবে, আপনি যখন আপনার ডাটাবেজে টাইমজোন ছাড়াই টাইমস্ট্যাম্প খুঁজে পান তখন সময়সীমা এবং সামারটাইমের সাথে সম্মতিতে মাসে মাসে বিভাজন তথ্যতে এটি কাজ করবে:

SELECT 
    "id", "Product", "Sale",
    date_trunc('month', 
        CASE WHEN 
            Extract(month from t."date") > 03 AND
            Extract(day from t."date") > 26 AND
            Extract(hour from t."date") > 3 AND
            Extract(month from t."date") < 10 AND
            Extract(day from t."date") < 29 AND
            Extract(hour from t."date") < 4
        THEN 
            t."date" at time zone '+03' -- Romania TimeZone offset + DST
        ELSE
            t."date" at time zone '+02' -- Romania TimeZone offset 
        END) as "date"
FROM 
    public."Table" AS t
WHERE 1=1
    AND t."date" >= '01/07/2015 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
    AND t."date" < '01/07/2017 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
GROUP BY date_trunc('month', 
    CASE WHEN 
        Extract(month from t."date") > 03 AND
        Extract(day from t."date") > 26 AND
        Extract(hour from t."date") > 3 AND
        Extract(month from t."date") < 10 AND
        Extract(day from t."date") < 29 AND
        Extract(hour from t."date") < 4
    THEN 
        t."date" at time zone '+03' -- Romania TimeZone offset + DST
    ELSE
        t."date" at time zone '+02' -- Romania TimeZone offset 
    END)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.