テーブルと1行の単位|テーブル・SELECT・条件抽出

このページはプロモーション(広告)を含みます。

テーブル・SELECT・条件抽出(初級・読む20分+演習30分)

この授業のゴール

仕事でどう使うか

SQLを書く前に、まず表を読みます。表の1行が何を表すかを取り違えると、正しい構文で書いても、数字の意味が変わります。「注文数」のつもりが「商品の行数」になっていた、という事故は実務で頻繁に起きます。

路線 この授業の使いどころ
DS(データサイエンティスト) 分析表の「1行=何か」を最初に確認する。ここがずれると、率の分母・分子がずれ、分析レポートの数字が誤る
ML(機械学習エンジニア) 学習データの1行が「顧客」か「注文」かで、予測の対象が変わる。同じ顧客が複数行あると、評価データに情報が漏れる
DX(DX推進・AI企画) KPI(Key Performance Indicator:重要業績評価指標)の定義書に「何を1件と数えるか」を書く。システム担当との認識合わせに使う
RS(研究者) 観測単位(被験者か、測定1回か)を明記する。同じ人の複数測定を独立な標本と数えると、結論が過信になる

この授業の目的は、SQLの文法よりも前に「表を正しく読む目」を作ることです。

前提

次の言葉を使います。不安があれば先に戻ってください。

SQL(Structured Query Language:データベースに問い合わせる言語)の経験は不要です。この授業のSQLは、実行 ボタンで画面内で動かせます。

身近な状況:「注文は何件?」に答えが3つある

ネットショップの担当者が「先月の注文は何件ですか」と聞かれました。手元には次の表があります。

注文表 orders(8行)の先頭部分:

order_id customer_id order_date status amount
1 101 2025-03-31 paid 3000
2 102 2025-04-01 paid 1200
3 101 2025-04-01 cancelled 2500

明細表 order_items(注文の中の商品ごとに1行)には、注文1のために2行(商品p1とp2)があります。

この状況で「件数」と言えそうな数字は3つあります。

  1. 注文表の行数:注文が何件あったか(8)
  2. 明細表の行数:商品の行が何行あるか(8)
  3. 注文した顧客の人数:何人が買ったか(5)

偶然、1と2はどちらも8ですが、意味は別物です。2は「注文1に商品が2行ある」ぶん増え、「明細のない注文(注文6)」ぶん減っています。どの表の何を数えるのかを決めないと、答えが決まりません。

下を実行して、表を眺めてみましょう。-- db: none は「空のデータベースから始める」印です。

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
SELECT * FROM customers;
SELECT * FROM orders;
SELECT * FROM order_items;

直感的な説明:表は名簿、1行は名簿の1人分

表(テーブル)は、同じ項目をもつ記録を並べた名簿のようなものです。

この「1行が表す単位」を粒度(りゅうど、grain)と呼びます。粒度が違う表は、数え方も違います。

表 1行の単位(粒度) 同じ顧客は何行?
customers 顧客1人 1行だけ
orders 注文1件 何度も注文すれば複数行
order_items 注文の中の商品1行 1注文に複数行もありえる

粒度の見分け方は、表の名前、主キー(行を1つに決める列)、列の名前を読むことです。order_items の主キーが (order_id, line_no) の組なら、「注文番号と行番号が決まれば1行に決まる」ので、1行=注文の中の1行だとわかります。

正確な定義:主キー・外部キー・行数と種類数

この授業で使う言葉を、正確に定義します。

$$\text{行数} \ge \text{種類数}$$

主キーの列なら、行数と種類数は一致します。主キーではない列(外部キー customer_id など)では、同じ値が複数行に現れるので、行数のほうが大きくなりえます。

関数の整理:

式 引数 戻り値 NULLの扱い
COUNT(*) なし(* は全列の意味) 整数:行の数 すべての行を数える
COUNT(列) 1つの列 整数:その列がNULLでない行の数 NULLは数えない
COUNT(DISTINCT 列) 1つの列 整数:NULLを除いた値の種類数 NULLは数えない

実行して確認します。

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
SELECT COUNT(*)                    AS order_rows,
       COUNT(DISTINCT order_id)    AS order_kinds,
       COUNT(DISTINCT customer_id) AS customer_kinds
FROM orders;

結果は order_rows=8、order_kinds=8、customer_kinds=5 です。order_id は主キーなので行数と種類数が同じ、customer_id は同じ顧客が複数回注文するので8行に対して5種類です。

段階付き例題:「注文した顧客は何人?」を3つの表で数える

問題:注文を1件以上した顧客の人数を求める。また、一度も注文していない顧客の人数も求める。

ステップ1:数える対象を決める。「人数」なので数えるのは顧客。顧客の一覧がある表は customers(1行=顧客1人)。

ステップ2:全顧客の人数を数える。customers は主キーが customer_id なので、行数がそのまま人数になる。

ステップ3:注文した顧客の人数を数える。orders は1行=注文1件で、同じ顧客が複数行に現れる。行数(8)を使うと注文件数になってしまうので、COUNT(DISTINCT customer_id) で種類数を数える。

ステップ4:差を求める。注文なしの顧客 = 全顧客 − 注文した顧客。

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
SELECT (SELECT COUNT(*) FROM customers)                    AS all_customers,
       (SELECT COUNT(DISTINCT customer_id) FROM orders)    AS ordered_customers,
       (SELECT COUNT(*) FROM customers)
       - (SELECT COUNT(DISTINCT customer_id) FROM orders)  AS never_ordered;

ステップ5:結果を読む。全顧客6人、注文した顧客5人、一度も注文していない顧客1人(106 渡辺)です。計算の式は $6 - 5 = 1$ です。

ステップ6:意味を確認する。購入率(顧客のうち購入した人の割合)は $5 \div 6 \approx 0.833$、つまり83.3%です。もし誤って注文の行数8を人数として使うと $8 \div 6 = 133\%$ となり、100%を超えるため誤りに気づけます。割合が100%を超えたら、分子の数え方を疑うのが検算の基本です。

((SELECT ...) は、小さな問い合わせの結果を1つの値として使う書き方です。詳しくは 「サブクエリ」(有料版) で学びます。)

操作して理解する:表の「キー」と粒度を自分で確かめる

次のSQLを実行し、結果を実行前に予想してから確認してください。

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
-- (1) 明細表の行数と、明細のある注文の種類数
SELECT COUNT(*) AS item_rows, COUNT(DISTINCT order_id) AS orders_with_items
FROM order_items;
-- (2) 明細が1行もない注文はどれ?
SELECT order_id FROM orders
WHERE order_id NOT IN (SELECT order_id FROM order_items);
-- (3) 同じ (order_id, line_no) が2行以上ある? 0行なら主キーが守られている
SELECT order_id, line_no, COUNT(*) AS n
FROM order_items GROUP BY order_id, line_no HAVING COUNT(*) > 1;

答えと読み方:

自分でも試してみましょう:(1) の COUNT(DISTINCT order_id) を COUNT(DISTINCT product_id) に変えると、商品の種類数(p1〜p7で7)が出ます。同じ表でも、数える列を変えると数えている対象が変わります。

発展:キーが守られない表と「見かけの1行」

実際の業務データでは、主キーを宣言していない表や、宣言していても意味の上で重複している表があります。

どの場合も、使う前に次の3点を確認する習慣を付けます。

  1. 主キー(またはそれに相当する列)で行数と種類数が一致するか。
  2. 1行=何かを、列名とサンプル行から言葉にできるか。
  3. 期間や状態(取消など)で、行が追加・上書き・削除されるのか。

なお、データベースの方言(MySQL、PostgreSQL、SQLiteなど)によって主キーの扱い(NULLの許容など)に細かな違いがあります。ここではSQLiteで説明しています。

よくある失敗

失敗1:COUNT(*) を「顧客数」として報告する

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
-- 誤り:注文表の行数は「注文件数」。顧客数ではない
SELECT COUNT(*) AS customers_wrong FROM orders;
-- 正しい:顧客の種類数
SELECT COUNT(DISTINCT customer_id) AS customers_right FROM orders;

誤りは8、正しくは5です。注文表の1行は注文1件なので、同じ顧客(101、102、103)が複数回数えられています。直し方:数えたい対象(顧客)の種類数を COUNT(DISTINCT customer_id) で数えるか、顧客表の行数を使う。

失敗2:粒度の違う表をそのまま足し算の元にする

注文表の amount(注文の合計金額)と、明細表の unit_price(商品1個の単価)は粒度も意味も違います。明細表の unit_price をそのまま合計しても、売上にはなりません。

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
-- 誤り:単価の合計。数量を掛けていないので、注文1の金額が合わない
SELECT SUM(unit_price) AS wrong_total FROM order_items WHERE order_id = 1;
-- 正しい:数量×単価の合計
SELECT SUM(quantity * unit_price) AS right_total FROM order_items WHERE order_id = 1;

誤りは2500(2000+500)、正しくは3000(2000×1 + 500×2)で、注文表の amount(3000)と一致します。直し方:明細の売上は「数量×単価」の合計で出し、注文表の金額と照合する。

失敗3:0・NULL・空欄を「同じ未入力」とみなす

注文4の金額は 0(無料サンプル)、注文6の金額は NULL(未記録)、注文7のクーポン欄は空文字 '' です。この3つは別の意味です。

-- db: none
CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT
);
INSERT INTO customers VALUES
  (101,'佐藤','東京都'),(102,'鈴木','大阪府'),(103,'高橋','東京都'),
  (104,'田中','愛知県'),(105,'伊藤','東京都'),(106,'渡辺','北海道');
CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  order_date TEXT NOT NULL,
  status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
  channel TEXT NOT NULL,
  amount INTEGER,
  coupon_code TEXT
);
INSERT INTO orders VALUES
  (1,101,'2025-03-31','paid','web',3000,NULL),
  (2,102,'2025-04-01','paid','app',1200,'SPRING'),
  (3,101,'2025-04-01','cancelled','web',2500,NULL),
  (4,103,'2025-04-10','paid','store',0,NULL),
  (5,104,'2025-04-15','refunded','app',1800,'SPRING'),
  (6,102,'2025-04-20','paid','web',NULL,NULL),
  (7,105,'2025-04-30','paid','web',1200,''),
  (8,103,'2025-05-01','paid','app',4000,'VIP');
CREATE TABLE order_items (
  order_id INTEGER NOT NULL,
  line_no INTEGER NOT NULL,
  product_id TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  unit_price INTEGER NOT NULL,
  PRIMARY KEY (order_id, line_no)
);
INSERT INTO order_items VALUES
  (1,1,'p1',1,2000),(1,2,'p2',2,500),(2,1,'p3',1,1200),(3,1,'p4',1,2500),
  (4,1,'p5',1,0),(5,1,'p6',1,1800),(7,1,'p3',1,1200),(8,1,'p7',2,2000);
SELECT order_id, amount, coupon_code,
       amount IS NULL     AS amount_is_null,
       coupon_code IS NULL AS coupon_is_null,
       coupon_code = ''   AS coupon_is_empty
FROM orders WHERE order_id IN (4, 6, 7);

注文4は金額0(NULLではない)、注文6は金額NULL、注文7のクーポンは空文字(NULLではない)です。「0」「欠損」「空欄」を一括りに集計すると、平均やデータ品質の数字が狂います。直し方:列ごとに「0は有効な値か」「空文字を欠損とみなすか」を決め、その定義を書いておく。詳しくは NULLと3値論理。

まとめ

用語

テーブル(表)(table)

同じ項目(列)をもつ記録(行)を並べたもの。データベースの基本単位。

粒度(grain)

表の1行が表す単位(顧客1人、注文1件、明細1行など)。

主キー(primary key)

表の行を1つに特定する列(または列の組)。重複もNULLも許されない。

外部キー(foreign key)

別の表の主キーを指す列。表どうしの関係を表す。

COUNT(DISTINCT 列)(COUNT DISTINCT)

重複を除いた値の種類数を数える。NULLは数えない。

よくある質問

なぜSQLを書く前に「1行の単位」を確認するのですか?

数える対象が決まらないと、COUNTやSUMの結果がどの量を表すのかが決まらないからです。構文が正しくても、顧客数のつもりで注文件数を出す事故が起きます。

COUNT(*) と COUNT(列) は何が違いますか?

COUNT(*) は行の総数、COUNT(列) はその列がNULLでない行の数です。NULLがない列なら同じ値になりますが、NULLがあると差が出ます。未入力の割合を調べるときにも使えます。

COUNT(DISTINCT 列) はいつも使えばよいですか?

いいえ。主キーの列では行数と同じなので不要です。重複の原因(結合で行が増えた等)を隠すために使うと、本物の重複まで消えて誤りの原因になります。何を数えたいかが「種類数」のときだけ使います。

主キーが宣言されていない表では、どうやって1行の単位を確認しますか?

列名とサンプル行から仮説を立て、COUNT(*) と COUNT(DISTINCT 候補の列) を比べます。一致すればその列は一意である可能性が高いです。それでも業務の担当者に定義を確認するのが確実です。

外部キーを宣言しておくと何が良いのですか?

存在しない顧客IDを持つ注文を登録できなくなり、データの整合性が守られます。また、表どうしの関係が読み手にわかり、結合の条件を間違えにくくなります。ただし分析用に取り込んだ表では宣言がないこともあるため、確認が必要です。

仕事の数字の「件数」はどう確認すべきですか?

報告する前に「何の1件か」を言葉にします。KPI定義書に『注文件数=注文表の取消を除く行数』のように、表・条件・粒度を書いておけば、担当者が変わっても同じ数字になります。

確認問題

問1 注文表(1行=注文1件)で、同じ顧客が複数回注文している。「顧客数」を最も適切に数える式はどれか。

  1. ① SUM(amount)
  2. ② COUNT(*)
  3. ③ COUNT(DISTINCT customer_id)
  4. ④ COUNT(order_id)
解答と解説

正解:③

同じ顧客が複数行に現れるので、重複を除いた種類数を数えます。

問2 「粒度(1行の単位)」の説明として最も適切なものはどれか。

  1. ① 表の1行が何を表すか
  2. ② 表に入れられる最大行数
  3. ③ 数値の小数点以下の桁数
  4. ④ 列の数
解答と解説

正解:①

粒度は、1行が顧客1人なのか注文1件なのかなど、行が表す単位のことです。

問3 主キーの性質として正しいものはどれか。

  1. ① 必ず数値でなければならない
  2. ② 同じ値が複数行にあってよい
  3. ③ NULLでもよい
  4. ④ 行を1つに特定でき、値が重複しない
解答と解説

正解:④

主キーは行を一意に決める列で、重複もNULLも許されません。

問4 明細表(1行=注文の中の商品1行)の行数が8、COUNT(DISTINCT order_id) が7だった。ここから言えることはどれか。

  1. ① 注文は8件ある
  2. ② 注文は7件で、そのうち1つ以上の注文に複数行の明細がある
  3. ③ 明細表には主キーがない
  4. ④ 顧客は7人いる
解答と解説

正解:②

行数が種類数より多いのは、同じ注文の明細が複数行あるためです。7は明細のある注文の種類数です。

問5 閲覧ログの user_id 列に NULL(未ログイン)が含まれる。COUNT(DISTINCT user_id) の結果について正しいものはどれか。

  1. ① エラーになる
  2. ② NULLを0として数える
  3. ③ NULLも1種類として数える
  4. ④ NULLは数えない
解答と解説

正解:④

COUNT(列) と COUNT(DISTINCT 列) はNULLを数えません。

問6 購入者数が5、全顧客数が6のとき購入率はいくつか。また、誤って注文の行数8を分子にするとどうなるか。

  1. ① 83.3%。誤ると133%になり、100%超で誤りに気づける
  2. ② 16.7%。誤ると75%になる
  3. ③ 50%。誤ると100%になる
  4. ④ 83.3%。誤りでも100%以下なので気づけない
解答と解説

正解:①

5÷6≒0.833。8÷6≒1.33で、割合が100%を超えるのは分子が違う印です。

次に学ぶこと

次は SELECTと列 で、SELECTで必要な列だけを取り出し、列名を付け、式で新しい列を作ります。条件で行を選ぶ方法は WHEREと条件 で扱います。

この授業の確認問題だけで習得とはしません。モジュール テーブル・SELECT・条件抽出 の総合テストと、別データの自力課題で判定します。

キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。

アプリを無料で開く有料版と無料版の違い