woshidan's blog

そんなことよりコードにダイブ。

ウィンドウ関数に触ってみる

下準備

http://sqlfiddle.com/ の Postgress SQL 9.6 でテスト。

CREATE TABLE books (
  id int,
  name varchar,
  author varchar,
  price int
);

INSERT INTO books
VALUES
(
  1,
  'Introduciton For Dog',
  'Pochi',
  200
);

INSERT INTO books
VALUES
(
  2,
  'High Performance For Dog',
  'Pochi',
  350
);

INSERT INTO books
VALUES
(
  3,
  'Master Of Dog',
  'Pochi',
  1000
);

INSERT INTO books
VALUES
(
  4,
  'Introduciton For Cat',
  'Tama',
  500
);

INSERT INTO books
VALUES
(
  5,
  'High Performance For Cat',
  'Tama',
  700
);

まずは集約関数

SELECT author, COUNT(*) 
FROM books 
GROUP BY(author);
// 結果
author  count
Tama    2
Pochi   3

はじめてのウィンドウ関数

// 関数をかける列を指定するイメージ(関数で使う列の値で行を並び替えて...みたいなイメージ)はGROUP BYに似ているが
// WINDOW関数の基本的な構文の場合、SELECT句にOVER(PARTITION BY 列) と書く
SELECT author, COUNT(*) OVER(PARTITION BY author) 
FROM books;
author   count
Pochi   3 // countで出ている数はGROUP BYの場合と同じだが、
Pochi   3 // ウィンドウ関数の場合は集約処理がなされていないので
Pochi   3 // 行がたくさんでてくる
Tama    2
Tama    2

ウィンドウ関数は

  • 集約関数と同じく特定の列でグループ化された行の中で処理をするけど
  • 集約のように1行にまとめるのではなく、1行ごとに結果が欲しい

という場合に使うと便利で、代表的なものとしてRANKがある。ウィンドウ関数が使用可能なのはSELECT句とORDER BY句。

SELECT author, name, RANK() OVER(ORDER BY price DESC) as rank 
FROM books;
author  name                        rank // ウィンドウ関数は処理を行う列以外もSELECTできる
Pochi   Master Of Dog               1    // 集約する際に集約に使わない行を消すが、その際、集約に使った列以外はどこを残すか、
Tama    High Performance For Cat    2    // といった問題が発生しないので表示できる状態にしてても困らないとか?
Tama    Introduciton For Cat        3
Pochi   High Performance For Dog    4
Pochi   Introduciton For Dog        5

一つのSQLの中に複数のウィンドウ関数を書くことができ、それぞれのウィンドウ関数に異なるOVER句を記述することが可能。

複数のウィンドウ関数で同じOVER句を使う場合は OVER(ORDER BY price DESC)ORDER BY price DESC の部分にWindow句で名前をつけることができて、OVER句内で参照することができる。

SELECT author, name, RANK() OVER price_order as rank 
FROM books
WINDOW price_order AS (ORDER BY price DESC);

参考: https://www.postgresql.jp/document/9.4/html/tutorial-window.html