めも

技術メモとその他

【postgres】group by 〜 first row 集計して最初の行をとる

 

select * from detail;

 

 product_id | item |    value     

------------+------+--------------

 000001     | 01   | 1111-1111-11

 000001     | 02   | 100000

 000001     | 03   | 100000

 000001     | 04   | in

 000001     | 05   | 100000

 000002     | 01   | 2222-1111-11

 000002     | 02   | 100000

 000002     | 03   | 100000

 000002     | 04   | out

 000002     | 05   | 100000

 000003     | 01   | 3333-1111-11

 000003     | 02   | 100000

 000003     | 03   | 100000

 000003     | 04   | in

 000003     | 05   | 100000

(15 rows)

 

select *,rank() over (partition by product_id 

order by item desc ) as rank 

from detail;

 

 product_id | item |    value     | rank 

------------+------+--------------+------

 000001     | 05   | 100000       |    1

 000001     | 04   | in           |    2

 000001     | 03   | 100000       |    3

 000001     | 02   | 100000       |    4

 000001     | 01   | 1111-1111-11 |    5

 000002     | 05   | 100000       |    1

 000002     | 04   | out          |    2

 000002     | 03   | 100000       |    3

 000002     | 02   | 100000       |    4

 000002     | 01   | 2222-1111-11 |    5

 000003     | 05   | 100000       |    1

 000003     | 04   | in           |    2

 000003     | 03   | 100000       |    3

 000003     | 02   | 100000       |    4

 000003     | 01   | 3333-1111-11 |    5

(15 rows)

 

あとはrank=1のものに条件を絞ればOK

【Postgresql】 テーブル全体を固定長データとして出力するサンプル

サンプルテーブルの構造は以下の通り

 

select * from nyukintable;

 id | siten | kokyakuid | nyukin | torihikibi 

----+-------+-----------+--------+------------

  1 | 東京  | 001       |  77500 | 2007-01-01

  2 | 大阪  | 002       |  56200 | 2007-01-02

  3 | 福岡  | 003       |  17900 | 2007-01-03

  4 | 東京  | 004       |  27000 | 2007-01-04

  5 | 大阪  | 005       |  71000 | 2007-01-05

  6 | 福岡  | 006       |  13100 | 2007-01-06

  7 | 東京  | 007       |    680 | 2007-01-07

  8 | 大阪  | 008       |   7600 | 2007-01-08

  9 | 福岡  | 009       |  61600 | 2007-01-09

 10 | 東京  | 010       |  28400 | 2007-01-10

 

1つの文字列に変換します

ついでにヘッダーもつけてみます

WITH read_str AS (

         SELECT rpad(nyukintable.id::text, 3, ' '::text) AS id,

            rpad(nyukintable.siten::text, 5, ' '::text) AS siten,

            rpad(nyukintable.kokyakuid::text, 8, ' '::text) AS kokyakuid,

            rpad(nyukintable.nyukin::text, 10, ' '::text) AS nyukin

           FROM nyukintable

        ), fix_header AS (

         SELECT '0001AAAABBBBCC'::text AS head

        ), data_rec AS (

         SELECT array_to_string(array_agg(ARRAY[read_str.id, read_str.siten, read_str.kokyakuid, read_str.nyukin]), ''::text) AS hurikomi

           FROM read_str

        )

 SELECT fix_header.head || data_rec.hurikomi

   FROM fix_header,

    data_rec;

 

結果

------------------------------------

 0001AAAABBBBCC1  東京   001     77500     2  大阪   002     56200     3  福岡   003     17900     4  東京   004     27000     5  大阪   005     71000     6  福岡   006     13100     7  東京   007     680       8  大阪   008     7600      9  福岡   009     61600     10 東京   010     28400     11 大阪   011     32700     12 福岡   012     46500     13 東京   013     10200     14 大阪   014     43000     15 福岡   015     48200     16 東京   016     83700     17 大阪   017     92400     18 福岡   018     17800     19 東京   019     91400     20 大阪   020     70300     21 福岡   021     37900     22 東京   022     3700      23 大阪   023     1900      24 福岡   024     91700     25 東京   025     6800      26 大阪   026     96600     27 福岡   027     55900     28 東京   028     65800     29 大阪   029     74400     30 福岡   030     76400     31 東京   031     90400     32 大阪   032     4300      33 福岡   033     16100     34 東京   034     63700     35 大阪   035     64000     36 福岡   036     83600     37 東京   037     19900     38 大阪   038     84900     39 福岡   039     3400      40 東京   040     16100     41 大阪   041     97400     42 福岡   042     1800      43 東京   043     1500      44 大阪   044     94100     45 福岡   045     62500     46 東京   046     4100      47 大阪   047     46200     48 福岡   048     51900     49 東京   049     7800      50 大阪   050     41200     

【Postgresql】 重複排除と先頭取得の併用(distinct on & lead)

サンプルテーブルの構造です

ch_dateはレート(rate)の変更を行った日付ですが、

レートの適用期間を算出したい(yyyy-mm-dd〜yyyy-mm-dd 0.001%)

a=# select * from rate_history order by ch_date;

       ch_date       |   rate    

---------------------+-----------

 2021-02-15 00:00:00 | 0.0008000

 2021-03-01 00:00:00 | 0.0010000

 2021-03-02 00:00:00 | 0.0010000

 2021-03-03 00:00:00 | 0.0010000

 2021-03-04 00:00:00 | 0.0020000

 2021-03-05 00:00:00 | 0.0020000

 2021-03-06 00:00:00 | 0.0020000

 2021-03-07 00:00:00 | 0.0030000

 2021-03-08 00:00:00 | 0.0030000

 2021-03-09 00:00:00 | 0.0040000

(10 rows)

 

変更日付でソート&重複除外します

# select ch_date,rate from

(select distinct on (rate) ch_date,rate from (select * from rate_history order by ch_date)a)c;

       ch_date       |   rate    

---------------------+-----------

 2021-02-15 00:00:00 | 0.0008000

 2021-03-01 00:00:00 | 0.0010000

 2021-03-04 00:00:00 | 0.0020000

 2021-03-07 00:00:00 | 0.0030000

 2021-03-09 00:00:00 | 0.0040000

(5 rows)

期間の終了日を次の変更日から1日前を計算して取得します

この行方向の移動にlead関数を利用します

# select 

ch_date,

coalesce(

 lead(ch_date,1,null) over (order by ch_date) + cast('-1 days' as interval) ,

 ch_date) as end_date,

rate 

from

(

select distinct on (rate) ch_date,rate from 

(select * from rate_history order by ch_date)a

)c;

       ch_date       |      end_date       |   rate    

---------------------+---------------------+-----------

 2021-02-15 00:00:00 | 2021-02-28 00:00:00 | 0.0008000

 2021-03-01 00:00:00 | 2021-03-03 00:00:00 | 0.0010000

 2021-03-04 00:00:00 | 2021-03-06 00:00:00 | 0.0020000

 2021-03-07 00:00:00 | 2021-03-08 00:00:00 | 0.0030000

 2021-03-09 00:00:00 | 2021-03-09 00:00:00 | 0.0040000

(5 rows)

 

【Postgresql】集計して、CSV形式にする方法

select * from nyukintable;

 id | siten | kokyakuid | nyukin | torihikibi 

----+-------+-----------+--------+------------

  1 | 東京  | 001       |  77500 | 2007-01-01

  2 | 大阪  | 002       |  56200 | 2007-01-02

  3 | 福岡  | 003       |  17900 | 2007-01-03

  4 | 東京  | 004       |  27000 | 2007-01-04

  5 | 大阪  | 005       |  71000 | 2007-01-05

  6 | 福岡  | 006       |  13100 | 2007-01-06

  7 | 東京  | 007       |    680 | 2007-01-07

  8 | 大阪  | 008       |   7600 | 2007-01-08

 

select siten,sum(nyukin) from nyukintable group by siten;

 siten |  sum   

-------+--------

 東京  | 598680

 福岡  | 686300

 大阪  | 978200

 

select array_to_string(array_agg(array[siten,sums]),',') from (select siten,cast(sum(nyukin) as text) as sums from nyukintable group by siten) a;

           array_to_string           

-------------------------------------

 東京,598680,福岡,686300,大阪,978200

(1 row)

【Postgresql】総合計を計算する

テーブルの構造とデータの状態です

 

select * from bs_summary ;

 agg_code |  debit  | credit 

----------+---------+--------

 1002     | 1000000 |       

 1001     | 1000000 |       

 2001     |         | 800000

 2002     |         | 800000

(4 rows)

 

各列の合計を最後に出力する

select coalesce(agg_code,'9999') as agg_code,

sum(debit) as debit,

sum(credit) as credit

from bs_summary

group by rollup(agg_code)

order by agg_code;

 

 agg_code |  debit  | credit  

----------+---------+---------

 1001     | 1000000 |        

 1002     | 1000000 |        

 2001     |         |  800000

 2002     |         |  800000

 9999     | 2000000 | 1600000

(5 rows)

 

【Postgresql】 generate_seriesを使ったシーケンス(日付)

select 

* 

from GENERATE_SERIES('2020-03-12'::timestamp, '2030-03-12'::timestamp, '6 month'::INTERVAL);

 

   generate_series   

---------------------

 2020-03-12 00:00:00

 2020-09-12 00:00:00

 2021-03-12 00:00:00

 2021-09-12 00:00:00

 2022-03-12 00:00:00

 2022-09-12 00:00:00

 2023-03-12 00:00:00

 2023-09-12 00:00:00

 2024-03-12 00:00:00

 2024-09-12 00:00:00

 2025-03-12 00:00:00

 2025-09-12 00:00:00

 2026-03-12 00:00:00

 2026-09-12 00:00:00

 2027-03-12 00:00:00

 2027-09-12 00:00:00

 2028-03-12 00:00:00

 2028-09-12 00:00:00

 2029-03-12 00:00:00

 2029-09-12 00:00:00

 2030-03-12 00:00:00

(21 rows)