PostgreSQL: PostgreSQL組み込み関数:詳細ガイド

最終更新:2026-08-26

1. 学習内容


2. ストーリー

AliceはEコマースのデータアナリストで、月末に月次売上レポートを作成する必要があります。レポートでは以下が求められます:

  1. order_date2025-June-30 形式に整形
  2. 顧客名+注文番号をレポート行のタイトルに連結
  3. NULL処理:欠損している割引値をデフォルトの0に
  4. 金額計算:税込総額と割引後の正味額を正確に計算
  5. シーケンスの使用:レポート行に連番を生成

AliceはPostgreSQLの組み込み関数を組み合わせてレポートを作成する必要があります。


3. 概念:数学関数

(1) 基本的な数学関数

関数 意味 結果
ABS(x) 絶対値 ABS(-15) 15
ROUND(x, n) n桁に四捨五入 ROUND(3.1415, 2) 3.14
CEIL(x) 切り上げ CEIL(3.2) 4
FLOOR(x) 切り捨て FLOOR(3.8) 3
MOD(x, y) 剰余 MOD(10, 3) 1
POWER(x, y) べき乗 POWER(2, 10) 1024
SQRT(x) 平方根 SQRT(144) 12
SIGN(x) 符号 SIGN(-5) -1
TRUNC(x, n) 切り捨て(小数部) TRUNC(3.1415, 2) 3.14

▶ サンプル:ROUNDで固定小数桁に丸める

SQL
SELECT
  unit_price,
  ROUND(unit_price, 0) AS rounded_0,
  ROUND(unit_price, 2) AS rounded_2
FROM products
WHERE category = 'Electronics';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ サンプル:CEIL / FLOORによる丸め

SQL
SELECT
  total_amount,
  CEIL(total_amount) AS ceil_value,
  FLOOR(total_amount) AS floor_value,
  total_amount - FLOOR(total_amount) AS decimal_part
FROM orders
WHERE order_status = 'completed';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) ROUND vs TRUNC vs CEIL/FLOOR

関数 動作 3.5 の結果 3.2 の結果 -3.5 の結果
ROUND(x) 最も近い整数に丸める 4 3 -4
TRUNC(x) 小数部を切り捨て 3 3 -3
CEIL(x) 切り上げ 4 4 -3
FLOOR(x) 切り捨て 3 3 -4

▶ サンプル:MOD剰余

SQL
SELECT
  order_id,
  total_amount,
  MOD(order_id, 10) AS partition_key,
  total_amount * POWER(1.08, 1) AS with_annual_tax
FROM orders
WHERE order_status = 'completed';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ サンプル:SQRTとPOWERの組み合わせ

SQL
SELECT
  unit_price,
  SQRT(unit_price) AS price_sqrt,
  POWER(unit_price, 1.0 / 3) AS price_cbrt
FROM products
WHERE unit_price > 0
ORDER BY unit_price DESC;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

4. 概念:文字列関数

(1) 大文字小文字と長さ

関数 意味 結果
LOWER(s) 小文字に変換 LOWER('Hello') hello
UPPER(s) 大文字に変換 UPPER('Hello') HELLO
INITCAP(s) 先頭文字を大文字化 INITCAP('hello world') Hello World
LENGTH(s) 文字数 LENGTH('PostgreSQL') 10
BIT_LENGTH(s) ビット長 BIT_LENGTH('A') 8
CHAR_LENGTH(s) LENGTHと同じ CHAR_LENGTH('ABC') 3

▶ サンプル:大文字小文字変換

SQL
SELECT
  product_name,
  LOWER(product_name) AS lower_name,
  UPPER(product_name) AS upper_name,
  INITCAP(LOWER(product_name)) AS title_name
FROM products
WHERE is_active = true;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) 連結と部分文字列

関数 意味 結果
CONCAT(s1, s2, ...) 連結(NULL安全) CONCAT('A', NULL, 'B') AB
CONCAT_WS(sep, s1, s2) 区切り文字付き連結 CONCAT_WS('-', 'A','B') A-B
`s1 s2` 連結(NULL安全でない)
SUBSTRING(s FROM n FOR len) 部分文字列 SUBSTRING('Hello' FROM 2 FOR 3) ell
LEFT(s, n) 左からn文字 LEFT('Hello', 3) Hel
RIGHT(s, n) 右からn文字 RIGHT('Hello', 2) lo

▶ サンプル:CONCAT vs ||

SQL
SELECT
  product_name,
  CONCAT(product_name, ' - $', unit_price) AS safe_concat,
  product_name || ' - $' || unit_price AS unsafe_concat,
  CONCAT_WS(' | ', product_name, category, unit_price::TEXT) AS ws_concat
FROM products;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) 検索と置換

関数 意味 結果
POSITION(sub IN s) 位置を検索 POSITION('sql' IN 'postgresql') 8
STRPOS(s, sub) 同上(引数が逆) STRPOS('postgresql', 'sql') 8
REPLACE(s, from, to) 置換 REPLACE('ABC', 'B', 'X') AXC
OVERLAY(s PLACING t FROM n) 上書き OVERLAY('XXXX' PLACING 'AB' FROM 2) XABX
SPLIT_PART(s, delim, n) 区切り文字で分割しn番目を取得 SPLIT_PART('A-B-C', '-', 2) B
TRIM(s) 前後の空白を除去 TRIM(' Hi ') Hi
LTRIM(s) 左の空白を除去 LTRIM(' Hi ') Hi
RTRIM(s) 右の空白を除去 RTRIM(' Hi ') Hi
RPAD(s, len, fill) 右パディング RPAD('Hi', 5, 'x') Hixxx
LPAD(s, len, fill) 左パディング LPAD('42', 5, '0') 00042
REVERSE(s) 逆順 REVERSE('ABC') CBA

▶ サンプル:SPLIT_PARTでCSVフィールドを解析

SQL
SELECT
  product_name,
  SPLIT_PART(category_path, '/', 1) AS top_category,
  SPLIT_PART(category_path, '/', 2) AS sub_category
FROM products
WHERE category_path LIKE '%/%';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ サンプル:REPLACEとTRIMの組み合わせ

SQL
SELECT
  TRIM(product_name) AS clean_name,
  REPLACE(product_name, '  ', ' ') AS no_double_spaces
FROM products
WHERE is_active = true;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ サンプル:LPADで数値を整形

SQL
SELECT
  LPAD(product_id::TEXT, 8, '0') AS formatted_id,
  product_name,
  unit_price
FROM products
ORDER BY product_id;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

5. 概念:日付関数

(1) 現在時刻の取得

関数 戻り値の型 説明
CURRENT_DATE DATE 現在の日付
CURRENT_TIME TIME WITH TZ 現在の時刻(タイムゾーン付き)
CURRENT_TIMESTAMP TIMESTAMP WITH TZ 現在の日付と時刻
NOW() TIMESTAMP WITH TZ CURRENT_TIMESTAMPと同じ
LOCALTIMESTAMP TIMESTAMP 現在の時刻(タイムゾーンなし)
CLOCK_TIMESTAMP() TIMESTAMP WITH TZ リアルタイムクロック(呼び出しごとに変化)

▶ サンプル:現在時刻の取得

SQL
SELECT
  CURRENT_DATE AS today,
  CURRENT_TIMESTAMP AS now_ts,
  NOW() AS now_func,
  LOCALTIMESTAMP AS local_ts;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) 日付演算

意味 結果の例
DATE '2025-01-15' + 7 日数を加算 2025-01-22
DATE '2025-01-15' - DATE '2025-01-01' 日数の差 14
NOW() + INTERVAL '30 days' インターバルを加算 30日後
NOW() - INTERVAL '1 year' インターバルを減算 1年前
AGE(end, start) インターバル記述 1 year 2 mons 3 days
AGE(timestamp) 現在からのインターバル

▶ サンプル:日付演算

SQL
SELECT
  order_date,
  order_date + 7 AS due_date,
  CURRENT_DATE - order_date AS days_ago,
  AGE(CURRENT_DATE, order_date) AS age_since_order
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '90 days';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) EXTRACTとDATE_TRUNC

使用法 意味 結果
EXTRACT(YEAR FROM ts) 年を抽出 EXTRACT(YEAR FROM NOW()) 2025
EXTRACT(MONTH FROM ts) 月を抽出 EXTRACT(MONTH FROM NOW()) 6
EXTRACT(DAY FROM ts) 日を抽出
EXTRACT(DOW FROM ts) 曜日(0=日曜) 1(月曜)
EXTRACT(QUARTER FROM ts) 四半期 2
EXTRACT(EPOCH FROM ts) Unixタイムスタンプ 1719500400
DATE_TRUNC('month', ts) 月初に切り捨て DATE_TRUNC('month', '2025-06-15') 2025-06-01
DATE_TRUNC('year', ts) 年初に切り捨て 2025-01-01

▶ サンプル:EXTRACTで日付部分を取得

SQL
SELECT
  order_date,
  EXTRACT(YEAR FROM order_date) AS order_year,
  EXTRACT(MONTH FROM order_date) AS order_month,
  EXTRACT(QUARTER FROM order_date) AS order_quarter,
  EXTRACT(DOW FROM order_date) AS weekday
FROM orders
WHERE order_status = 'completed';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ サンプル:DATE_TRUNCで月次集計

SQL
SELECT
  DATE_TRUNC('month', order_date) AS month_start,
  COUNT(*) AS order_count,
  SUM(total_amount) AS monthly_revenue
FROM orders
WHERE order_status = 'completed'
  AND order_date >= DATE_TRUNC('year', CURRENT_DATE)
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY month_start;

Output:

TEXT 📖 参照専用
 count 
-------
     5
(1 row)

(4) TO_CHARとTO_DATE

関数 目的
TO_CHAR(ts, fmt) 時刻→文字列 TO_CHAR(NOW(), 'YYYY-Month-DD')
TO_DATE(s, fmt) 文字列→日付 TO_DATE('2025-06-15', 'YYYY-MM-DD')
TO_TIMESTAMP(s, fmt) 文字列→タイムスタンプ TO_TIMESTAMP('2025-06-15 14:30', 'YYYY-MM-DD HH24:MI')

一般的な書式テンプレート:

テンプレート 意味 出力例
YYYY 4桁の年 2025
YY 2桁の年 25
Month 完全な月名 June
MON 省略月名 Jun
MM 2桁の月 06
DD 2桁の日 15
HH24 24時間制 14
MI 30
SS 45

▶ サンプル:TO_CHAR日付整形

SQL
SELECT
  order_id,
  TO_CHAR(order_date, 'YYYY-Month-DD') AS formatted_date,
  TO_CHAR(order_date, 'YYYY-MM-DD HH24:MI:SS') AS full_datetime,
  TO_CHAR(total_amount, 'FM$999,999.00') AS formatted_amount
FROM orders
WHERE order_status = 'completed';

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ サンプル:TO_DATEで文字列を日付に変換

SQL
SELECT
  TO_DATE('2025-06-15', 'YYYY-MM-DD') AS parsed_date,
  TO_DATE('15/06/2025', 'DD/MM/YYYY') AS eu_date,
  TO_DATE('Jun 15 2025', 'Mon DD YYYY') AS us_date;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

6. 概念:条件関数

(1) COALESCE

COALESCE(val1, val2, ...) は最初のNULLでない引数を返し、最も一般��なNULL処理関数です。

結果
COALESCE(NULL, NULL, 'default') default
COALESCE(100, 0) 100
COALESCE(NULL, 0) 0

▶ サンプル:COALESCEで欠損割引を処理

SQL
SELECT
  product_name,
  unit_price,
  discount_rate,
  COALESCE(discount_rate, 0) AS safe_discount,
  unit_price * (1 - COALESCE(discount_rate, 0)) AS net_price
FROM products;

Output:

TEXT 📖 参照専用
 count 
-------
     5
(1 row)

(2) NULLIF

NULLIF(val1, val2) は2つの値が等しい場合にNULLを返し、そうでなければval1を返します。ゼロ除算エラーを防ぐためによく使われます。

結果
NULLIF(100, 100) NULL
NULLIF(100, 0) 100
100 / NULLIF(0, 0) NULL(エラーの代わりに)

▶ サンプル:NULLIFでゼロ除算を防止

SQL
SELECT
  product_name,
  unit_price,
  total_sold,
  unit_price / NULLIF(total_sold, 0) AS revenue_per_unit
FROM products
WHERE is_active = true;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) GREATEST / LEAST

関数 意味 結果
GREATEST(a, b, c) 最大値を返す GREATEST(10, 20, 5) 20
LEAST(a, b, c) 最小値を返す LEAST(10, 20, 5) 5

▶ サンプル:GREATEST / LEAST

SQL
SELECT
  product_name,
  unit_price,
  COALESCE(discount_rate, 0) AS discount,
  unit_price * (1 - GREATEST(COALESCE(discount_rate, 0), 0.5)) AS capped_net_price,
  LEAST(unit_price, 999.99) AS price_cap
FROM products
WHERE is_active = true;

Output:

TEXT 📖 参照専用
 count 
-------
     5
(1 row)

(4) 条件関数の比較

関数 シナリオ NULL処理
COALESCE(a, b) デフォルト値を提供 最初のNULLでない値を返す
NULLIF(a, b) 値が等しい場合にNULL NULLを処理しない
GREATEST(a, b) 最大値を取得 いずれかがNULLならNULLを返す
LEAST(a, b) 最小値を取得 いずれかがNULLならNULLを返す

7. 概念:シーケンス関数

(1) シーケンス操作関数

関数 意味
NEXTVAL('seq_name') インクリメントして次の値を返す NEXTVAL('order_id_seq') → 1001
CURRVAL('seq_name') 現在のセッションの最後のNEXTVALを返す CURRVAL('order_id_seq') → 1001
SETVAL('seq_name', n) シーケンスの現在値を設定 SETVAL('order_id_seq', 5000)
SETVAL('seq_name', n, false) 値を設定、次のNEXTVALはnを返す SETVAL('order_id_seq', 5000, false)

▶ サンプル:NEXTVALで番号を生成

SQL
INSERT INTO orders (order_id, customer_id, total_amount, order_date)
VALUES (NEXTVAL('order_id_seq'), 1001, 299.99, CURRENT_DATE);

Output:

TEXT 📖 参照専用
INSERT 0 1

▶ サンプル:CURRVALで現在値を表示

SQL
SELECT
  NEXTVAL('report_seq') AS report_number,
  CURRVAL('report_seq') AS current_seq;

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) SETVALでシーケンスをリセット

呼び出し 次のNEXTVALが返す値
SETVAL('seq', 100) 101
SETVAL('seq', 100, false) 100
SETVAL('seq', 1, false) 1(先頭にリセット)

▶ サンプル:SETVALでシーケンスをリセット

SQL
-- シーケンスを1から再開するようにリセット
SELECT SETVAL('order_id_seq', 1, false);

-- シーケンスを特定の高い値に設定(例:データ移行後)
SELECT SETVAL('order_id_seq', (SELECT MAX(order_id) FROM orders));

Output:

TEXT 📖 参照専用
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

8. フローチャート:関数の選択

100%
flowchart TD
    A[必要な操作は?] --> B{データ型は?}
    B -->|数値| C{何が必要?}
    B -->|文字列| D{何が必要?}
    B -->|日付| E{何が必要?}
    B -->|NULL処理| F[COALESCE / NULLIF]
    C -->|丸め| G[ROUND / TRUNC]
    C -->|整数に丸め| H[CEIL / FLOOR]
    C -->|計算| I[ABS / MOD / POWER / SQRT]
    D -->|連結| J[CONCAT / ||]
    D -->|部分文字列| K[SUBSTRING / LEFT / RIGHT]
    D -->|置換| L[REPLACE / SPLIT_PART]
    D -->|大文字小文字| M[LOWER / UPPER / INITCAP]
    D -->|トリム| N[TRIM / LTRIM / RTRIM]
    E -->|現在時刻| O[NOW / CURRENT_TIMESTAMP]
    E -->|部分抽出| P[EXTRACT]
    E -->|切り捨て| Q[DATE_TRUNC]
    E -->|整形| R[TO_CHAR]
    E -->|解析| S[TO_DATE / TO_TIMESTAMP]

    style A fill:#e1f5fe
    style F fill:#c8e6c9

9. 総合的な例

Aliceは完全な月次売上レポートを��成しました。

SQL
-- ステップ1: 日付整形付き月次収益レポート
SELECT
  TO_CHAR(DATE_TRUNC('month', order_date), 'YYYY-Month') AS report_month,
  COUNT(*) AS order_count,
  SUM(total_amount)::NUMERIC(12,2) AS gross_revenue,
  SUM(total_amount * 0.08)::NUMERIC(12,2) AS tax_collected,
  SUM(total_amount * 1.08)::NUMERIC(12,2) AS total_with_tax
FROM orders
WHERE order_status = 'completed'
  AND order_date >= DATE_TRUNC('year', CURRENT_DATE)
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY report_month;

-- ステップ2: 文字列整形とNULL処理付き商品サマリー
SELECT
  LPAD(p.product_id::TEXT, 6, '0') AS product_code,
  INITCAP(LOWER(p.product_name)) AS display_name,
  CONCAT('$', ROUND(p.unit_price, 2)) AS price_label,
  COALESCE(p.discount_rate, 0) AS discount,
  ROUND(p.unit_price * (1 - COALESCE(p.discount_rate, 0)), 2) AS net_price,
  LEAST(ROUND(p.unit_price * (1 - COALESCE(p.discount_rate, 0)), 2), 999.99) AS capped_price
FROM products p
WHERE p.is_active = true
  AND p.unit_price > NULLIF(p.cost_price, 0)
ORDER BY net_price DESC;

-- ステップ3: 年数計算付き顧客注文サマリー
SELECT
  CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
  COUNT(o.order_id) AS total_orders,
  SUM(o.total_amount)::NUMERIC(12,2) AS lifetime_value,
  AGE(MAX(o.order_date), MIN(o.order_date)) AS customer_span,
  EXTRACT(YEAR FROM AGE(CURRENT_DATE, c.register_date)) AS years_since_join
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id
WHERE o.order_status = 'completed'
GROUP BY c.customer_id, c.first_name, c.last_name, c.register_date
ORDER BY lifetime_value DESC
FETCH FIRST 25 ROWS ONLY;

❓ よくある質問

Q CONCATと || の違いは?
A CONCATはNULLを無視します(NULLでない部分を連結します)が、|| はいずれかのオペランドがNULLの場合、結果全体がNULLになります。NULL安全な連結にはCONCATまたはCONCAT_WSを使用してください。
Q ROUND(2.5)は2か3か?
A PostgreSQLのROUNDは「銀行家の丸め」(偶数への丸め)を使用するため、ROUND(2.5) = 2、ROUND(3.5) = 4となります。これは一部の言語の丸め方と異なります。
Q EXTRACT(DOW FROM date)は日曜日に0を返しますか、7を返しますか?
A DOWは0〜6を返し、0が日曜日、1が月曜日、6が土曜日です。ISO標準(1=月曜日、7=日曜日)にはEXTRACT(ISODOW FROM date)を使用してください。
Q DATE_TRUNCは時間単位に切り捨てられますか?
A はい。DATE_TRUNCはマイクロ秒、ミリ秒、秒、分、時、日、週、月、四半期、年、十年、世紀、千年紀を含む精度レベルをサポートしています。
Q COALESCEは異なる型を受け付けますか?
A はい、ただしすべての引数が暗黙的に同じ型に変換可能である必要があります。例えば、COALESCE(NULL, 0, 0.5)はすべての値をNUMERICに変換します。
Q NEXTVALを呼び出す前にCURRVALを使用できますか?
A いいえ。CURRVALは現在のセッションでそのシーケンスに対してNEXTVALが既に呼び出されている必要があり、そうでなければ「currval of sequence is not yet defined in this session」というエラーが発生します。
Q TO_CHARで数値を整形する際のFMプレフィックスの意味は?
A FM(Fill Mode)は先頭のゼロと末尾のスペースのパディングを除去します。TO_CHAR(42, 'FM00000') = '42'(先頭ゼロなし)ですが、TO_CHAR(42, '00000') = '00042'です。
Q 日付の差におけるAGEと減算の違いは?
A DATE1 - DATE2 は整数の日数を返し、AGE(DATE1, DATE2) は年、月、日を含むINTERVALを返します(例:1 year 2 mons 3 days)— より人間に優しいですが、減算より精度は低くなります。

📖 まとめ


📝 練習問題

  1. products から product_nameunit_price を選択し、CONCAT で価格ラベル($99.99 形式)を作成し、ROUND で小数点以下2桁に丸め、価格の降順でソートするクエリを書いてください。

  2. ⭐⭐ 2025年の月次売上レポートを生成するクエリを書いてください:DATE_TRUNC('month', order_date) で月ごとにグループ化し、TO_CHARYYYY-MM 形式に整形し、月次注文数と合計金額(NUMERIC(12,2))を計算し、COALESCE でNULLの可能性がある割引を処理してください。

  3. ⭐⭐⭐ 顧客ごとのレポート行を生成するクエリを書いてください:CONCAT_WS で名前を結合し、AGE で顧客の登録期間を計算し、EXTRACT で登録年を抽出し、GREATEST で割引を50%にキャップし、NULLIF で平均注文額計算時のゼロ除算を防ぎ、LPAD で顧客IDを6桁の番号に整形し、最後に NEXTVAL('report_seq') でレポート行のシーケンスを生成してください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%