システムアーキテクト試験を受験してきました

システムアーキテクト試験を受験しました。
初めての高度情報試験でしたが、いやはや、手がとても疲れました。
色々書きたいことはありますが、まずは感想だけを書き留めておきます。
なお、4月に応用情報技術者試験に合格しているので、午前Ⅰは免除でした。

 

午前Ⅱ

午前Ⅱは四肢択一が25問、これを40分(10:50~11:30)で解きます。
高度情報試験の午前問題集で勉強するには、今一つ体系立っていないので、過去問演習で十分というのがインターネット上の情報の見解でした。

今回は体感としては7割近くが新出問題だったような気がします。
共通フレーム2013からの出題が多く、知ってれば条件反射的に回答できるが、知らないと予想して当てていかないといけない感じでした。

 一応、全て埋めましたが、最悪ここで脱落しているかもしれません。少し不安。

 

(2018/10/22追記ここから)

午前ⅡはIPAから正答が出ていましたね。

IPA 独立行政法人 情報処理推進機構:問題冊子・配点割合・解答例・採点講評(2018、平成30年)

自己採点したら20/25で普通に8割越えでした。
何とか突破できてそうです。

(2018/10/22追記ここまで)

午後Ⅰ

午後Ⅰは記述式問題で、4問中2問選択して解きます。
第4問目は組み込み系の問題であり、今年もそうなっていました。
12:30~14:00の90分間で解きます。

 試験勉強時にも15回程度時間を計って演習していますが、
大体1問につき30分前後で回答できていたので、今回も2問で60分、30分程度余ると思っていました。

 

午後の問題は選択式なので、どの問題を選ぶかが重要で、
そのために数分程度時間を割く必要があるのですが、
私は組み込み系出身なので、問4を選択することをあらかじめ決めていました。
その上で、もう一つ、出身ではない分野から1つ選ぶ必要があります。

できるだけ選択に時間を使いたくなかったので、
演習をする過程で、2つの選択に関するルールを決めました。

  1. お金が絡む問題は避ける
  2. データベースが出てくる問題は避ける

1.については、演習の結果、私の苦手な範囲であることがわかったため、
2.については、苦手ではないが、解くのに時間がかかることがわかったためです。

今回は、問1がデータベース系、問3がお金が絡む問題だったので、問2を選択することにしました。
ネットワークの図があったので一瞬怯みましたが、問題文にはネットワーク系のものが見当たらなかったので、一安心。

 一応、2問で70分くらいでしたが、見直し等をしていたら
制限時間90分を使い切ってしまいました。

 

午後Ⅱ

やってきました論述式の午後Ⅱ。一般に高度情報試験の要と言われています。
午後Ⅱは自分の経験をもとに3500文字程度論述しなければなりません。
実にB5ノート4ページ分、ぎっしり文字を詰め込んだ感じです。
試験時間2時間(14:30~16:30)の長丁場です。

 採点官には、本当に受験者が自分の経験を元に論述しているのか
調べる由がないので、多少の妄想・誇張を交えるのは普通ですが、
全く経験のないことを論述するのは相当に骨が折れる作業ですので、
やはり、多少なりとも経験したことがあるテーマを題材に論述を進めるのが
午後Ⅱの基本的方針となります。

 私は先述の通り組み込み系出身なので、問3しか選択肢はありません。
アプリケーション系も数回トライしてみましたが、やはり全く書けませんでした。
試験本番も、真っ先に問3に丸を付けて、システム概要をさっさと埋め、問題本文に取り組みました。

 題材はデータ量の増加への対応。
AIやIoTとは相性が良さそうですが、何分私が生業としているのは
RTOSも使わなければネットワークにも繋がっていない、
原価にして数千円レベルの組み込み製品。
さて、どうしたものか。

 結論から言えば、今まで演習でテーマにしていたものを少し膨らませた形にして、何とかストーリーを組み立てることができました。
演習では、30分で構成を決め、60分でひたすら書く、という感じだったのですが、今回は構成に多少難儀して40分弱かけてしまいました。

それでも20分余裕があると思ったら、解答用紙が大きい大きい。
今までB5ノートに25文字×32行=800文字で書いていたのに、1文字当たりのサイズが長さ比で1.5倍くらい大きい。
その分書く時間もかかるし、鉛筆の減りも早いし、手も疲れる。
午前Ⅱからの手の酷使で、後半は結構しんどかったです。

それでも何とか書き進め、書き終えたころには試験終了10分前。
途中退出して帰ろうと思ったのに、そんな余裕はありませんでした。
汚い文字をちょこちょこ直していたら、終了時刻に。
そんな感じで私のSA試験は終わりました。

今回の試験で学んだことは、また別途記事を改めてお伝えしようと思います。

(追記ここから:2018/12/22)

無事、合格しました。

stacked-tip.hateblo.jp

(追記ここまで:2018/12/22)

システムアーキテクト試験の午前対策Webサイト

システムアーキテクト試験などの高度情報試験は、
記述・論述式の午後問題の対策に焦点が当てられますが、
午前問題も侮ってはいけません。
例え午前Ⅰが免除であっても、むしろ免除だからこそ、しっかり午前Ⅱ対策をしないといけません。

応用情報の時みたいに、きっと過去問演習ができるWebサイトがあるだろうと思ったら、
やっぱりありました。

システムアーキテクト 過去問

こちらのサイトには、軽い解説もついています。

必ず受かる情報処理技術者試験-高度メニュー

午前Ⅱは25問の四肢択一です。6割合格ならば15問正解すればクリアです。

組み込み系の人がシステムアーキテクト試験に合格したブログを読んでみた

システムアーキテクト試験合格体験記はWeb上にもいくつか存在しますが、
下記のものは組み込み系の人の合格体験記なので、参考になるところが多かったので紹介します。

dimeiza.hatenablog.com

組み込みSEがシステムアーキテクト試験の計画を立ててみた

4月に受験した応用情報技術者試験は、6月に無事合格の通知が来ました。
元々プロジェクトマネージャー試験(PM)の午前Ⅰ免除のために受けたので、
目標は達成されたわけですが、いかんせんPMは4月にしか受験できない。
しかし折角の午前Ⅰ免除なので、何か10月に受けてみようかということで、
システムアーキテクト試験(SA)を受験してみようと思います。

早い話が、記述・論述試験の雰囲気に慣れることが目的ですが、
とは言え5000円近くの受験料を支払うので、合格を狙いたいところです。

しかし私は組み込みSEなので、SAが想定している業務システム系ではないのですよね。
すると、午後Ⅰ・Ⅱでどの問題を選択するかがカギになるわけです。

午後Ⅰ

  • 90分
  • 記述式
  • 4問から2問を選択して回答
  • 4問の内、1問は必ず組み込み系、残り3問は業務系

午後Ⅱ

  • 120分
  • 論述式
  • 3問から1問を選択して回答
  • 3問の内、1問は必ず組み込み系、残り2問は業務系

テキストはひとまず以下のものを購入しました。
「平成30-01年度 システムアーキテクト合格教本」技術評論社

このテキスト、買ってから気が付いたのですが、
組み込み系の問題が割愛されています。何てこった。

とりあえず午後Ⅰ・Ⅱを数問解いてみましたが、

  • 午後Ⅰは、業務系でも得意な分野と苦手な分野があり、得意な分野に絞れば解けそう
  • 午後Ⅱは、業務系のシステムアーキテクトの仕事が全く想像できず、組み込み系に絞ろうと思う

となりそうです。
ですので、午後Ⅱの組み込み系の問題解説が掲載されているテキストを、別途買おうかと考えています。

(2018/11/3追記 ここから)
結局、午後Ⅱの問3(組込み系)の問題が載っている、
松田幹子ら『うかる!システムアーキテクト2018年度版』翔泳社も購入しました。

(2018/11/3追記 ここまで)

ER図の記法3選

ER図(実体関連図:Entity-relationship Diagram)は、主にデータベースを扱う際に、データモデルを表現するのに使用します。
ER図の記法はいくつかあるのですが、ここでは、メジャーな3つを紹介します。

後で述べますが、同じER図を描くのに、それぞれの分野で別々の記法を使用しているため、実はこの2つの記法は同じことを示していた(描き方が違うだけ)ということに気付かないことがあります(私がそうでした)。

バックマン線図

1969年にバックマン(C. W. Bachman)が発表した記法*1
線・矢印を使ったシンプルな記法であり、情報処理技術者試験応用情報技術者試験等)ではこの記法が使われています。

シンプルであることは欠点でもあり、他の2つの比較して、ぱっと見た時の意味が分からないのが、バックマン線図の欠点です。原著では下図に対して、

The direction of the arrow is read to mean that each employee is a member of a set of employees that belong to a particular department, and further, that each department has such a set of employees.

とあるだけで、ここに矢印を導入した理由や妥当性には触れていません。
基本的には「そういうものだ」と覚えるしかないのです。

Crow's Foot (カラスの足)記法

1980年代に、コンサルティングファームCACIにてバーカー(R. Barker)が考案した記法(バーカーはのちにオラクルに入社し、RDBMSソフトを開発)。
見た目が分かりやすいので、ER図の実践的教育の場面で良く使用されますが、表現できる内容が少ないので、複雑な関係性を表記する際には、この記法はあまり使われません。

クラス図(UML

UML(統一モデリング言語:Unified Modeling Language)は、オブジェクト指向分析・設計の際に使用される記法群です。UMLの中に色々な記法が含まれており、クラス図はその中のひとつです。

多重度が数字で表記されるのでわかりやすく、また、それ以外の様々な情報を表現することができます。しかし、ER図としては機能が過剰であるので、ER図として用いられることはあまりありません。

図の転載元

  1. 平成30年度 春期 応用情報技術者試験 午後 問題
  2. Data structure diagrams
  3. The Details of Conceptual Modelling Notations are Important - A Comparison of Relationship Normative Language
  4. UML Class Diagram - explanation & concepts

応用情報技術者試験「データベース」に出てきたSQLを眺めてみる

ONの後ろが空欄

ONの後ろの空欄は、「○○.●● = △△.●●」の形の条件文が入ります。
例1) 平成29年春期

SELECT 申請書.申請書ID,
       申請書.タイトル,
       申請書.申請日
       ユーザ.ユーザ名,
       部署マスタ.部署名
FROM 申請書
    INNER JOIN 承認申請 ON 申請書.申請書ID = 承認申請.申請書ID
    INNER JOIN ユーザ ON 申請書.申請者ユーザID = ユーザ.ユーザID
    INNER JOIN 部署マスタ ON ユーザ.部署ID = 部署マスタ.部署ID
WHERE (承認申請.承認申請状態 NOT IN ('可決', '否決'))
      AND
      ((申請書.申請者ユーザID = :ユーザID)
       OR
       (申請書.申請書ID
        IN (SELECT DISTINCT 申請書ID
            FROM 承認者情報
                --この行のON以降が空欄
                INNER JOIN 承認申請 ON 承認者情報.承認申請ID = 承認申請.承認申請ID
            WHERE 承認者情報.承認者ユーザID = :ユーザID )
      ))

SELECT 申請書.申請書ID, 申請書.タイトル, t1.項目値 AS 金額, t2.項目値 AS 支払日
                                         --下の2行のON以降が共に空欄
    FROM 申請書 INNER JOIN 申請書項目 t1 ON 申請書.申請書ID = t1.申請書ID
                INNER JOIN 申請書項目 T2 ON 申請書.申請書ID = t2.申請書ID
    WHERE
    ((申請書.書式ID = '購買' AND t1.項目キー = 'amount' AND t2.項目キー = 'pay_data') OR
     (申請書.書式ID = '契約' AND t1.項目キー = 'pay_initial' AND t2.項目キー = 'start_date'))
    AND (承認申請.申請書ID = 申請書.申請書ID AND 承認申請.承認申請状態 = '可決')

例2) 平成23年秋期

SELECT 明細行番号, 日付, 費用種別.費用種別名, 金額
FROM 申請明細 INNER JOIN 費用種別
    ON 申請明細.費用種別コード = 費用種別.費用種別コード    --この行のON以降が空欄
WHERE 申請明細.申請書番号 = :申請書番号 AND 費用種別.証憑フラグ = 'Y'
ORDER BY 明細行番号

GROUP BYの後ろが空欄

GROUP BYの後ろの空欄には、SELECTの後ろに続く項目名が入ります。
例1)平成29年秋期

SELECT 品名コード, 品目名, 産地コード, 産地名,
SUM(t2.単価 * t1.パレット数) AS 合計返品金額, SUM(t1.パレット数) AS 合計返品数量
    FROM 返品 t1
        INNER JOIN 販売明細 t2 USING (販売番号, 販売明細番号)
        INNER JOIN 仕入明細 USING(仕入番号,仕入明細番号)
        INNER JOIN 品目 USING (品目コード)
        INNER JOIN 産地 USING (産地コード)
    WHERE 返品日 = CURRENT_DATE
    GROUP BY 品目コード,品目名,産地コード,産地名    --この行のGROUP BY以降が空欄
    ORDER BY 品目コード ASC, 産地コード ASC

COALESCEを含むSELECT文

COALESCE()関数が出てきたら、検索結果にNULLが含まれる場合があることを意味します。
この時、多くの場合外挿(OUTER JOIN)が行われていています。
例1) 平成28年春期

--このSELECT文にはCOALESCE()がある
SELECT ST.確認年月日, ST.店舗ID, ST.商品ID, COALESCE(SS.日間販売数量, 0),
    ST.日間在庫数量
FROM
    (SELECT SC.確認年月日, SC.店舗ID, SC.商品ID,
        AVG(SC.在庫数量) AS 日間在庫数量
     FROM 在庫 SC
     GROUP BY SC.確認年月日, SC.店舗ID, SC.商品ID) ST
     LEFT OUTER JOIN    --ここにLEFT OUTER JOINがいる
    (SELECT SL.販売年月日, SL.店舗ID, SD.商品ID,
        SUM(SD.販売数量) AS 日間販売数量
     FROM 販売 SL
        INNER JOIN 販売詳細 SD ON SL.販売ID = SD.販売ID
     GROUP BY SL.販売年月日, SL.店舗ID, SD.商品ID) SS
      ON ST.確認年月日 = SS.販売年月日
         AND ST.店舗ID = SS.店舗ID
         AND ST.商品ID = SS.商品ID

SELECT SF.売上年月, SF.店舗ID, IT.商品分別ID,
    AVG(SF.日間販売数量) AS 平均販売数量, AVG(SF.日間在庫数量) AS 平均在庫数量
FROM
    (SELECT TO_YYYYMM(SA.売上年月日) AS 売上年月, SA.店舗ID, SA.商品ID,
        SA.日間販売数量, SA.日間在庫数量
     FROM 売上ファクト SA) SF
    INNER JOIN 商品 IT ON SF.商品ID = IT.商品ID
GROUP BY SF.売上年月, SF.店舗ID, IT.商品分類ID
ORDER BY SF.売上年月 DESC,SF.店舗ID ASC,平均在庫数量 DESC

例2) 平成25年春期

INSERT INTO 発言キーワード重み (キーワードID, 重み)
--このSELECT文にはCOALESCE()がある
SELECT キーワード.キーワードID, COALESCE(OMOMI.CNT,0)
FROM キーワード
    LEFT OUTER JOIN    --ここにLEFT OUTER JOINがいる(ここは空欄であった)
    (SELECT 発言キーワード.キーワードID, COUNT(*) AS CNT
     FROM 発言キーワード
        INNER JOIN 発言 ON 発言.発言ID = 発言キーワード.発言ID
     WHERE 発言.社員番号 IS NULL
     GROUP BY 発言キーワード.キーワードID) OMOMI
    ON キーワード.キーワードID = OMOMI.キーワードID


SELECT 発言.発言ID, SUM(発言キーワード重み.重み) AS WEIGHT
FROM 発言
    INNER JOIN 発言キーワード ON 発言.発言ID = 発言キーワード.発言ID
    INNER JOIN 発言キーワード重み
        ON 発言キーワード.キーワードID = 発言キーワード重み.キーワードID
WHERE 発言.否定的フラグ = '1'
GROUP BY 発言.発言ID
ORDER BY WEIGHT DESC

平成28年秋期

SELECT t1.会員番号, t1.氏名, t6.商品分類番号,
    t6.商品分類名, SUM(t4.商品単価 * t4.個数) AS 購入金額合計
FROM 会員 t1
    INNER JOIN (SELECT t2.購入番号, t2.会員番号
        FROM 購入 t2 WHERE t2.購入日時 > :一年前) t3 ON t1.会員番号 = t3.会員番号
    INNER JOIN 購入明細 t4 ON t3.購入番号 = t4.購入番号
    INNER JOIN 商品 t5 ON t4.商品番号 = t5.商品番号
    INNER JOIN 商品分類 t6 ON t5.商品分類番号 = t6.商品分類番号
GROUP BY t1.会員番号, t1.氏名, t6.商品分類番号, t6.商品分類名

DECLARE cur CURSOR FOR
    SELECT t2.会員番号, t2.購入番号, t2.購入金額
    FROM 購入 t2
    WHERE t2.購入ステータス = '完了'
    AND t2.購入日時 <= :判定対象期限
    AND t2.判定処理状態 <> '判定処理済み'
    ORDER BY t2.会員番号,t2.購入日時 ;
UPDATE 会員 t1 SET t1.会員種別 = '一般会員';
SET current_kaiin_no = 0;
SET goukei = 0;
OPEN cur;
fetch_loop: LOOP
    FETCH cur INTO kaiin_no, kounyu_no, kounyu_kingaku;
    IF kaiin_no <> current_kaiin_no THEN
        SET current_kaiin_no = kaiin_no;
        SET update_flag = 0;
        SET goukei = 0;
    END IF;
    IF update_flag = 0 THEN
        SET goukei = goukei + kounyu_kingaku;
        UPDATE 購入番号 = kounyu_no;
            WHERE t2.購入番号 = kounyu_no;
        IF goukei >= 50000 THEN
            UPDATE 会員 t1 SET t1.会員種別 = '特別会員' WHERE t1.会員番号 = kaiin_no;
            SET update_flag = 1;
        END IF;
    ELSE
        UPDATE 購入 t2 SET t2.判定処理状態 = '繰越し' WHERE t2.購入番号 = kunyu_no;
    END IF;
END LOOP fetch_loop;
CLOSE cur;

平成27年秋期

WITH RECURSIVE 関連部署(部署ID, 部署名, 上位部署ID) AS (
    SELECT 部署.部署ID, 部署.部署名, 部署.上位部署ID
        FROM 部署 WHERE 部署.上位部署ID IS NULL
            AND :年月日 BETWEEN 部署.適用開始年月日 AND 部署.適用終了年月日
UNION ALL
    SELECT 部署.部署ID, 部署.部署名, 部署.上位部署ID
        FROM 部署, 関連部署 WHERE 部署.上位部署ID = 関連部署.部署ID
            AND :年月日 BETWEEN 部署.適用開始年月日 AND 部署.適用終了年月日
)
SELECT 部署ID, 部署名, 上位部署ID FROM 関連部署

平成27年春期

SELECT AC.*
FROM アクセスログ AC
WHERE EXISTS
    (SELECT * FROM 非営業日 NS
     WHERE AC.操作年月日 = NS.非営業年月日)

SELECT AC.*
FROM アクセスログ AC
    INNER JOIN 利用者 US ON AC.利用者ID = US.利用者ID
    INNER JOIN サーバ SV ON AC.サーバID = SV.サーバID
WHERE AC.操作結果 = 'F'
    AND US.部署ID <> SV.部署ID

平成26年春期

SELECT COUNT(*) AS 判定結果
FROM Webユーザ
WHERE ユーザID = :ユーザID
    AND パスワードハッシュ値 = HASH(:パスワード)

SELECT A.船便番号, A.船便名, C.座席クラス番号, C.座席クラス名,
    COUNT(*) AS 空席数
FROM 船便 A
    INNER JOIN 座席クラス C ON B.座席クラス番号 = C.座席クラス番号
WHERE A.出発日 = :出発日
  AND A.出発地 = :出発地
  AND A.到着地 = :到着地
  AND B.空席状況 = '0'
GROUP BY A.船便番号,A.船便名,C.座席クラス番号,C.座席クラス名

平成25年秋期

SELECT タイトルマスタ.タイトル, 会員マスタ.会員ID, 会員マスタ.氏名,
    会員マスタ.連絡先, 貸出予約.予約日時
FROM (タイトルマスタ
    INNER JOIN 貸出予約 ON タイトルマスタ.タイトルID = 貸出予約.タイトルID)
    INNER JOIN 会員マスタ ON 貸出予約.会員ID = 会員マスタ.会員ID
WHERE タイトルマスタ.タイトルID = :予約タイトルID
    AND 貸出予約.予約日時 = (SELECT MIN(貸出予約.予約日時) FROM 貸出予約
                             WHERE 貸出予約.タイトルID = :予約タイトル
                               AND 貸出予約.予約ステータス = '予約中')

平成24年春期

CREATE VIEW 統合検索
    (書籍名, 著者名, 出版社名, ISBN番号, 図書館名, 貸出可能冊数) AS
SELECT 書籍A.書籍名, 書籍A.著者名, 書籍A.出版社名, 書籍A.ISBN番号,
    'A市図書館', COUNT(書籍A.書籍番号) FROM 蔵書A, 書籍A
WHERE 蔵書A.書籍番号 = 書籍A.書籍番号
    AND 蔵書A.蔵書番号 NOT IN (SELECT 貸出記録A.蔵書番号 FROM 貸出記録A
                               WHERE 貸出記録A.返却日 IS NULL)
GROUP BY 書籍名, 著者名, 出版社名, 書籍A.ISBN番号
UNION
SELECT 書籍B.書籍名, 書籍B.著者名, 書籍B.出版社名, 書籍B.ISBN番号,
    'B市図書館', COUNT(書籍B.ISBN番号) FROM 蔵書B, 書籍B
WHERE 蔵書B.ISBN番号 = 書籍B.ISBN番号
    AND 蔵書B.蔵書番号 NOT IN (SELECT 貸出記録B.蔵書番号 FROM 貸出記録B
                               WHERE 貸出記録B.返却日 IS NULL)
GROUP BY 書籍名, 著者名, 出版社名, 書籍B.ISBN番号


CREATE VIEW 統合貸出予約
    (蔵書番号, 書籍名, 著者名, 出版社名, ISBN番号, 図書館名, 貸出状況) AS
SELECT 蔵書A.蔵書番号, 書籍A.書籍名, 書籍A.著者名, 書籍A.出版社名,
    書籍A.ISBN番号, 'A市図書館', 蔵書A.貸出状況) FROM 蔵書A, 書籍A
WHERE 蔵書A.書籍番号 = 書籍A.書籍番号
    AND 蔵書A.貸出状況 = '貸出可'
UNION
SELECT 蔵書B.蔵書番号, 書籍B.書籍名, 書籍B.著者名, 書籍B.出版社名,
    書籍B.ISBN番号, 'B市図書館', 蔵書B.貸出状況) FROM 蔵書B, 書籍B
WHERE 蔵書B.ISBN番号 = 書籍B.ISBN番号
    AND 蔵書B.貸出状況 = '貸出可'

平成23年秋期

SELECT 明細行番号, 日付, 費用種別.費用種別名, 金額
FROM 申請明細 INNER JOIN 費用種別
    ON 申請明細.費用種別コード = 費用種別.費用種別コード
WHERE 申請明細.申請書番号 = :申請書番号 AND 費用種別.証憑フラグ = 'Y'
ORDER BY 明細行番号


SELECT 申請書.組織コード, 組織.組織名,
    SUM (申請明細.金額) AS 組織交通費合計
FROM 申請書, 申請明細, 組織
WHERE 申請明細.日付 BETWEEN :指定月開始日 AND :指定月終了日
    AND 申請書.申請書番号 = 申請明細.申請書番号
    AND 申請書.組織コード = 組織.組織コード
GROUP BY 申請書.組織コード, 組織.組織名
ORDER BY 申請書.組織コード

平成23年特別

CREATE TABLE 新刊 (書籍番号 INTEGER, ジャンル INTEGER,
    PRIMARY KEY(書籍番号),
    FOREIGN KEY(書籍番号)
    REFERENCES 書籍(書籍番号))

DELETE FROM 新刊;
INSERT INTO 新刊 (書籍番号, ジャンル)
    SELECT 書籍番号, ジャンル FROM 書籍 WHERE 発行年月日 + 60 > :今日;


CREATE TABLE 購入傾向
    (顧客番号 INTEGER, ジャンル INTEGER, 購入冊数 INTEGER,
     PRIMARY KEY(顧客番号, ジャンル),
     FOREIGN KEY(顧客番号)
     REFERENCES 顧客(顧客番号))

DELETE FROM 購入傾向;
INSERT INTO 購入傾向 (顧客番号, ジャンル, 購入冊数)
    SELECT 注文.顧客番号, 書籍.ジャンル, SUM(注文明細.数量)
    FROM 注文, 注文明細, 書籍
    WHERE 注文.注文年月日+180>:今日
    AND 注文.注文番号 = 注文明細.注文番号
    AND 注文明細.書籍番号 = 書籍.書籍番号
    GROUP BY 注文.顧客番号, 書籍.ジャンル;


SELECT 書籍.書籍番号, 書籍.書籍名, 書籍.書籍説明 FROM 書籍, 新刊, 購入傾向
    WHERE 書籍.書籍番号 = 新刊.書籍番号
    AND 購入傾向.顧客番号 = :顧客番号
    AND 書籍.ジャンル = 購入傾向.ジャンル
    AND 購入傾向.購入冊数 * 10 > :購入総冊数


UPDATE 購入傾向 SET 購入冊数 =
    (SELECT 購入傾向.購入冊数 + 注文明細.数量 FROM 注文明細, 書籍
     WHERE 注文明細.注文番号 = :注文番号 AND 注文明細.注文明細番号 = :注文明細番号
     AND 注文明細.書籍番号 = 書籍.書籍番号 AND 書籍.ジャンル = 購入傾向.ジャンル)
WHERE 購入傾向.顧客番号 = :顧客番号
AND 購入傾向.ジャンル IN
    (SELECT 書籍.ジャンル FROM 注文明細, 書籍
     WHERE 注文明細.注文番号 = :注文番号 AND 注文明細.注文明細番号 = :注文明細番号
     AND 注文明細.書籍番号 = 書籍.書籍番号)

平成22年秋期

CREATE TABLE 請求
(請求書番号 CHAR(5),
顧客番号 CHAR(5), 請求日 CHAR(8), 計上年月 CHAR(6), 請求額 NUMERIC(10),
買上額 NUMERIC(10), 消込額 NUMERIC(10),
PRIMARY KEY (請求書番号),
FOREIGN KEY(顧客番号) REFERENCES 顧客(顧客番号))


SELECT 顧客番号, SUM(入金額-消込額)
    FROM 入金
    WHERE 入金日 <= :今月度末日
      AND 入金額 > 消込額
    GROUP BY 顧客番号

平成22年春期

SELECT t.店舗番号, t.店舗名, SUM(m.受注金額) AS 金額
FROM (店舗 t INNER JOIN (SELECT j.受注店舗番号, j.受注番号 FROM 受注 j
           WHERE j.受注日付 BETWEEN :指定月開始日 AND :指定月終了日) p
           ON t.店舗番号 = p.受注店舗番号)
          INNER JOIN 受注明細 m ON p.受注番号 = m.受注番号
GROUP BY t.店舗番号, t.店舗名
ORDER BY t.店舗番号


SELECT m.出荷店舗番号, SUM(m.受注金額) AS Web売上分
FROM 受注明細 m, 受注 j
WHERE (j.受注店舗番号 = 'A09999' ) AND ( j.受注番号 = m.受注番号 ) AND
      (j.受注日付 BETWEEN :指定月開始日 AND :指定月終了日)
GROUP BY m.出荷店舗番号
ORDER BY m.出荷店舗番号


SELECT t.店舗番号, t.店舗名, SUM(m.受注金額) AS 金額
FROM 店舗 t LEFT OUTER JOIN
    (SELECT j.受注店舗番号, j.受注番号 FROM 受注 j
        WHERE j.受注日付 BETWEEN :指定月開始日 AND :指定月終了日) p
            INNER JOIN 受注明細 m ON p.受注番号 = m.受注番号
    ON t.店舗番号 = p.受注店舗番号
GROUP BY t.店舗番号, t.店舗名
ORDER BY t.店舗番号

平成21年春期

SELECT TempTbl.商品番号, SUM(TempTbl.小計)
FROM (SELECT 注文明細.商品番号, 注文明細.数量 AS 小計
      FROM 注文明細
          INNER JOIN 商品 ON 注文明細.商品番号 = 商品.商品番号
      WHERE 注文明細.注文番号 = :注文番号
          AND 商品.セットフラグ = '0'
      UNION ALL
      SELECT セット商品.子商品番号 AS 商品番号,
               セット商品.数量 * 注文明細.数量 AS 小計
      FROM 注文明細
          INNER JOIN 商品 ON 注文明細.商品番号 = 商品.商品番号
          INNER JOIN セット商品 ON 商品.商品番号 = セット商品.セット商品番号
      WHERE 注文明細.注文番号 = :注文番号
          AND 商品.セットフラグ = '1') TempTbl
GROUP BY TempTbl.商品番号

SELECT DISTINCT 注文明細.注文明細番号, 注文明細.商品番号, 商品.商品名,
    注文明細.数量, 注文明細.販売単価, 注文明細.数量 * 注文明細.販売単価,
    CASE WHEN 新商品モデル.新商品番号 IS NOT NULL THEN '新モデルあり'
    ELSE '' END
FROM 注文明細
    LEFT OUTER JOIN 新商品モデル
        ON 注文明細.商品番号 = 新商品モデル.旧商品番号
    INNER JOIN 商品 ON 注文明細.商品番号 = 商品.商品番号
WHERE 注文明細.注文番号 = :注文番号
ORDER BY 注文明細.注文明細番号

SQLの構文を整理する(その①:SELECT構文)

応用情報技術者試験の午後の問題でデータベースを選ぼうと計画していますが、
(どの分野が得点しやすいのかざっと調べたところ、
 データベースが取りやすそうだったという理由です)
SQLは実務で使ったこともないのでサッパリです。

なので、まずは構文を覚えようかなと思い、整理してみます。

SELECT [フィールド] FROM [テーブル]

  • [テーブル]の中の[フィールド]だけを抽出する構文
  • [フィールド]はカンマで区切ることで、複数指定することができる

SQLZOO SELECT basicsの1.の回答欄に、
以下のように入力し「Submit SQL」をクリックしてみましょう。

SELECT population
FROM world

すると、すべての国の「population」のフィールドが表示されます。

今度は以下のように入力し「Submit SQL」をクリックしてみましょう。

SELECT population, gdp
FROM world

すると、すべての国の「population」と「gdp」のフィールドが表示されます。

SELECT [フィールド] FROM [テーブル] WHERE [条件]

  • 選択した[フィールド]の中で、[条件]を満たすものだけを表示する

ちなみに、"where"という英単語は「どこ」という意味の他、
接続詞として使うと「〜において」、「ここで、〜とする」という意味になります。
SQLZOO SELECT basicsの1.の回答欄に、
以下のように入力し「Submit SQL」をクリックしてみましょう。

SELECT population
FROM world
WHERE name = 'Germany'

すると、「population」のフィールドのうち、「name」が「Germany」のものだけが表示されます。

先ほどと同様、複数のフィールドを選択することもできます。

SELECT population, gdp
FROM world
WHERE name = 'Germany'

条件式には、AND, OR, NOTなどが使用できます。

SELECT population, gdp
FROM world
WHERE name = 'Germany' OR name = 'France'

と入力すれば、「Germany」と「France」の「population」「gdp」を表示することができます。
しかし、上記の例のように、同じフィールドに対し複数の条件を設定する場合は、
INを利用した方が楽です。
SQLZOO SELECT basicsの2.の回答欄に、
以下のように入力し「Submit SQL」をクリックしてみましょう。

SELECT name, population
FROM world
WHERE name IN ('Sweden', 'Norway', 'Denmark')

すると、「population」のフィールドのうち、
「name」が「Sweden」「Norway」「Denmark」のものが表示されます。
(この例では一緒に「name」も表示しています。

また、数字の範囲指定には、各種等号・不等号(=, <, >, <=, >=, <>*1)の他、
BETWEENも使用できます。
SQLZOO SELECT basicsの3.の回答欄に、
以下のように入力し「Submit SQL」をクリックしてみましょう。

SELECT name, area
FROM world
WHERE area BETWEEN 200000 AND 250000

すると、「area」が20万以上25万以下の「name」と「area」が表示されます。

*1:≠を意味する記号として、<>の他に!=も使用できます。