「データベースを使う上での基本 2つ」フォローその2

データベースを使う上での基本 2つ」で最後の方に紹介した書籍「SQL 書き方ドリル」内の主なSQL についてもやはりDB2 for IBM i (V5R4/V6R1) で実行してみました。

大半は特に問題なくすいすい実行していけると思いますが、大きな考慮点が2つあります。

最初にご理解いただきたい考慮点は以下の2つになります。

たとえば、↓のように書籍には載っていますが、

SELECT AVG(PRICE) AS 平均単価
FROM PRODUCTS;

↓のように英数字で表現した別名に書き換える必要があります。

SELECT AVG(PRICE) AS HEIKIN
FROM PRODUCTS;

↓ のように解答例に載っていますが

SUBSTR(CAST(SALEDATE AS VARCHAR),1,7) AS 年月

DB2 for i の場合は↓のいずれかのように変更する必要があります。

SUBSTR(CAST(SALEDATE AS CHAR(10)),1,7) AS NENGETSU
SUBSTR(CAST(CHAR(SALEDATE, ISO),1,7) AS NENGETSU
SUBSTR(CAST(CHAR(SALEDATE),1,7) AS NENGETSU

その他にも、応用問題の「その7」で

SUBSTR(CAST(PAYDATE AS VARCHAR),1,4) = '2007'

と"年"を取り出しているところがありますが、DB2 の場合は

YEAR(PAYDATE) = '2007'

と書くこともできますので、かえってわかりやすいかもしれません。

応用問題の「その9」で

WHEN (SUBSTR(CAST(S.SALEDATE),1,7) = '2007-6') THEN S.QUANTITY * P.PRICE ELSE 0

とあるところも、YEAR() 関数と MONTH() 関数を使って↓のように書くこともできます。

WHEN (YEAR(S.SALEDATE) = '2007' AND MONTH(S.SALEDATE) ='6') THEN S.QUANTITY * P.PRICE ELSE 0 END

単元最初の問題と、応用問題についてはすべて V5R4/V6R1 のDB2 for IBM i で実行できました。
(結果カラムの別名/相関名については英数字に直し、日付関数はDB2 の考慮事項に則った上、です)

その他も、添付のCD 内にあるリファレンスに各データベース毎の考慮事項が載っているので、これを参照しながら書籍を内容を進めていっていただければ、そんなに問題はないと思います。

該当リファレンスの中にその名も「DB2 を使う上での全般的な注意」という記載があり、たとえばその中の「データの型変換に関するご注意」には先述の日付型の変換についての考慮点が載っています。
CHAR() 関数を使うやり方が紹介されていますが、もちろんCAST() 関数で行ってもかまいません。

「第2章その5 列同士で演算を行う」で「問題「社員の健康状態を一覧で出してくれ」の書籍に記載の解答では、DB2 の場合、エラーとなります。」と明確に書いてあります。
ですので、書籍本文に載っている解答例そのままではDB2 では動かない、のが正解です。
「エラーを回避したSQL を以下に記載します」として付属 CD 内の HTML に載っているSQL で DB2 for IBM i  も同様にエラーを回避することができます。

応用問題についてもさまざまな考慮点が載っています。

あと、書籍内の「実行結果」と照らし合わせたりすると、添付のテーブル作成用のスクリプトに定義されている桁数の違いなどによって、若干の差があります。
create_for_db2.sql  内の以下の 2 テーブルについて、それぞれ Price と Amount の小数点以下値の桁数を変えてあげるといいでしょう。

CREATE TABLE Products (
 ProductID            INTEGER NOT NULL,
 ProductCode          INTEGER,
 ProductName          VARCHAR(100),
 Price                DECIMAL(7, 2),
 CategoryID           INTEGER
);

CREATE TABLE Salary (
 SalaryID             INTEGER NOT NULL,
 PayDate              DATE,
 Amount               DECIMAL(9, 3),
 EmployeeID           INTEGER
);

最後に、これは添付リファレンスの考慮事項には載っていないのですが、
応用問題の「その2」と「その9」については、解答例そのままのSQL では↓のようなエラーになります。

「SQL 状態: 42601
ベンダー・コード: -199
メッセージ: [SQL0199] キーワードBYは必要でない。」

実は、これは相関名がついていないためのエラー(意図的なのか単なる誤植のようなものなのかはわかりません…)です。
「その9」の例で言うと、一番最後にある ORDER BY の直前でカッコを閉じている直後に AS X という文字を追加してあげるだけで、実行可能なSQL になります。

SELECT
  PRODUCTID, PRODUCTNAME, HANBAI6, HANBAI7,
  CASE WHEN HANBAI6 < HANBAI7 THEN '↑' WHEN HANBAI6 = HANBAI7 THEN '→' ELSE '↓' END AS ZOGEN_TO6, HANBAI8,
  CASE WHEN HANBAI7 < HANBAI8 THEN '↑' WHEN HANBAI7 = HANBAI8 THEN '→' ELSE '↓' END AS ZOGEN_TO7
FROM
  ( SELECT P.PRODUCTID, P.PRODUCTNAME,
    SUM(CASE WHEN S.SALEDATE IS NULL THEN 0 WHEN (YEAR(S.SALEDATE) = '2007' AND MONTH(S.SALEDATE) ='6') THEN S.QUANTITY * P.PRICE ELSE 0 END) AS HANBAI6, 
    SUM(CASE WHEN S.SALEDATE IS NULL THEN 0 WHEN (YEAR(S.SALEDATE) = '2007' AND MONTH(S.SALEDATE) ='7') THEN S.QUANTITY * P.PRICE ELSE 0 END) AS HANBAI7,
    SUM(CASE WHEN S.SALEDATE IS NULL THEN 0 WHEN (YEAR(S.SALEDATE) = '2007' AND MONTH(S.SALEDATE) ='8') THEN S.QUANTITY * P.PRICE ELSE 0 END) AS HANBAI8
    FROM
      PRODUCTS AS P LEFT OUTER JOIN SALES S ON P.PRODUCTID = S.PRODUCTID
    GROUP BY
      P.PRODUCTID,
      P.PRODUCTNAME)  AS X
ORDER BY PRODUCTID;

これは、SQL というものが最初の文字から順に構文チェックを行う性質上、こういうエラーになってしまっています。このケースでは、くれぐれもメッセージをそのまま真に受けないようにしてくださいね。
ま、これは別にDB2 for IBM i に限ったことではないのですが、エラーメッセージはそのまま受け取るべきケースと、単にエラーのありそうな場所を暗示するだけの場合と両方あるのでなかなか難しいものですね。

iForum: 「データベースを使う上での基本 2つ」フォローその2
http://www.iforum.ne.jp/article.php/20090331022947454