SQLを学び直す その③

前回の続きです。

mei98.hatenablog.com

 

検索結果の加工方法

前回、前々回の記事の方法で抽出したデータを加工する方法です。

加工とは、例えば「降順に並べ替え」たり「重複を除外する」ことです。

 

DISTINCT

DISTINCTは、重複している行を取り除きます。

使い方は次の通り

SELECT DISTINCT 出荷先
FROM 注文票

/* 重複が取り除かれた出荷先データが表示される */

データの種類を取得したい場面で役立つ。

 

ORDER BY

指定した列の値を基準に、並び替えをします。

 

使い方は次の通り

SELECT *
FROM 売上
ORDER BY 業績表 ASC

/* 売上が低い順に表示される */
SELECT *
FROM 売上
ORDER BY 業績表 DESC

/* 売上が高い順に表示される */

 

ASCは昇順、DESCは降順に並び替えられる。

 

OFFSET / FETCH

一部の行だけを取得します。

使い方は次の通り

SELECT *
FROM 売上
ORDER BY 業績表
OFFSET 2 ROWS
FETCH NEXT 3 ROWS ONLY

/* 2~5行目だけ表示される */

なお、MySQLではサポートされていないので、以下の方法を使う

SELECT 費目,出金額
FROM 売上
ORDER BY 業績表
LIMIT 4 OFFSET 1

/* 2~5行目だけ表示される */

 

UNION

和集合を求める集合演算子

SELECT文をUNIONで繋いで記述すると、結果が足し合わされる。

 

使い方は次の通り

SELECT 名前, 性別, 住所 FROM クラスA
 UNION
SELECT 名前, 性別, 住所 FROM クラスB

/* クラスAとクラスBのデータが合体する */

片方のテーブルにしかないデータを結合する場合は、次のような使い方もできる

SELECT NULL as 国籍,名前, 性別, 住所 FROM クラスA
 UNION
SELECT 国籍,名前, 性別, 住所 FROM クラスB

/* クラスAとクラスBのデータが合体する。クラスAの国籍列はすべてNULL */

 

EXCEPT

差集合を求める集合演算子

SELECT文をEXCEPTで繋いで記述すると、両テーブルに存在する行以外が出力する。

使い方は次の通り

SELECT 出身小学校 FROM クラスA
EXCEPT
SELECT 出身小学校 FROM クラスB

/* クラスAとクラスBの両テーブルに存在する行以外のデータが出力 */

 

INTERSECT

積集合を求める集合演算子

SELECT文をINTERSECTで繋いで記述すると、両テーブルに存在する行が出力する。

使い方は次の通り

SELECT 出身小学校 FROM クラスA
INTERSECT
SELECT 出身小学校 FROM クラスB

/* クラスAとクラスBの両テーブルに存在する行のデータが出力 */

 

CASE演算子

CASE演算子は、SQL文中の条件分岐を行う機能。

使い方は次の通り

SELECT 学生名
    CASE 
        WHEN 点数 >= 60 THEN '合格'
        ELSE '不合格'
    END AS 結果
FROM 成績表;


/* 60点以上なら合格、60点未満なら不合格と表示される。 */

 

さまざまな関数

特定のタスクを実行するための機能。

例えば「COUNT」であれば、行数を取り出すことができる。

SELECT COUNT(*) FROM 成績表;

/* 成績表の行数がカウントされる。 */

「LENGTH」であば、文字列の長さを取得することができる。

SELECT LENGTH(生徒名) FROM 成績表;

/* 成績表の生徒名の文字列の長さが取得される。 */

関数は、DBMSごとに動作が異なるため、公式ドキュメントを参照する必要性アリ。

 

主な関数は次の通り

関数 説明
LENGTH

文字列の長さを求める

TRIM 空白を削除する
REPLACE 置換
SUBSTRING 指定文字目から指定文字分を抽出する
CONCAT 文字列を連結する
TRIM 空白を削除する
ROUND 四捨五入
TRANC 指定桁で切り捨てる
TRIM 空白を削除する
POWER べき乗
CURRENT_TIMESTAMP 現在日時(年,月,日,時,分,秒)
CURRENT_DATE 現在日付(年,月,日)
CURRENT_TIME 現在時刻(時,分,秒)
CAST 型のキャスト
COALESCE 最初に登場するNULL以外の値を返却する

 

・・・次の記事に続きます

SQLを学び直す その②

前回の続きです。

SQLを学び直す その① - mei98’s diary

 

WHERE句

WHERE句は、以下の特徴があります。

  1. 行の絞り込みをする
  2. SELECT、UPDATE、DELETE文で使う
  3. WHEREの後ろに条件式を記述する

 

WHEREで使う比較演算子

NULLの判定方法

  • NULLであることを判定する場合
IS NULL
  • NULLではないことを判定する場合
IS NOT NULL

 

LIKE演算子

部分一致の検索をする演算子

LIKE演算子で使えるパターン文字は以下の通り

命令文 説明
%

0文字以上の文字列

_ 1文字

 

使い方は次の通り

SELECT * 
FROM 社員
WHERE 名前 LIKE '%田%'

/* 名前に「田」がつく行が取り出される */

 

BETWEEN演算子

データの範囲を指定する演算子

使い方は次の通り

SELECT * 
FROM 社員
WHERE 年齢 BETWEEN 20 AND 30

/* 年齢が20~30の行が取り出される */

 

IN / NOT IN 演算子

指定の値に合致したデータを取り出す演算子

使い方は次の通り

SELECT * 
FROM 社員
WHERE 役職 IN ('一般社員','係長')

/* 役職が「一般社員」「係長」の行が取り出される */
SELECT * 
FROM 社員
WHERE 役職 NOT IN ('一般社員','係長')

/* 役職が「一般社員」「係長」以外の行が取り出される */

 

ANY / ALL 演算子

指定の条件と値に合致したデータを取り出す演算子

使い方は次の通り

SELECT * 
FROM 社員
WHERE 基本給 < ANY (200000,300000,400000)

/* 基本給が、値リストのいずれかより大きい行が取り出される */
SELECT * 
FROM 社員
WHERE 基本給 < ALL (200000,300000,400000)

/* 基本給が、値リストのすべてより大きい行が取り出される */

 

論理演算子

NOT、OR、ANDのこと。

優先順位としてはNOT > OR > ANDの並び。

 

 

・・・次の記事に続きます

SQLを学び直す その①

お仕事でSQLを使うことになったので、勉強します。

基本情報を取得するときに触れたことはあるのですが、意味不明だったので学び直し。

 

まずは基礎の「き」

学んだ内容をメモのように書き起こします。

 

SQL文のルール

SQL文の終了を、セミコロンで表せる

SELECT *
FROM 家計簿;      /* SELECT文終了 */
DELETE FROM 家計簿
WHERE ID = 1; /* DELETE文終了 */

コメント

  • ハイフン2つ
SELECT *
FROM 家計簿;      -- コメント
  • /* */で囲む
SELECT *
/*
コメント
*/
FROM 家計簿;      /* コメント */

4大命令

命令文 説明
SELECT

行の内容を取得する。

UPDATE 行の内容を書き換える
DELETE 行を削除する
INSERT 行にデータを追加する

 

SELECT文

SELECT *
FROM 家計簿;

基本的には、1行目にSELECT、2行目にFROMを記述する。

1行目のSELECTには、この命令文の後に使いたい列の名前を書く。

*を記述すれば、すべての列を取得することができる。

2行目のFROMには、取得するデータが格納されているテーブルを指定する。

3行目以降には、WHEREなどの修飾を続けて記述し、細かく条件を加えられる。

 

「AS」のキーワードをつけて、別名を定義することも可能。

SELECT 経費 AS COST  /* 「経費」が「COST」になる */
FROM 家計簿 AS MONEYBOOK /* 「家計簿」が「MONEYBOOK」になる */

 

UPDATE文

UPDATE 家計簿
SET 入金額 = 99999
WHERE ・・・

基本的には、1行目にUPDATE、2行目にはSET句を記述する。

1行目のUPDATEには、更新したいデータが存在するテーブル名を記述する。

2行目のSETには、更新したい列名、イコールの後に書き換えたいデータを記述する。

3行目以降には、WHEREなどの修飾を続けて記述し、細かく条件を加えられる。

 

DELETE文

DELETE FROM 家計簿
WHERE ・・・

基本的には、1行目にDELETE FROM、2行目にはWHERE句を記述する。

1行目のDELETE FROMには、更新したいデータが存在するテーブル名を記述する。

2行目以降には、WHEREなどの修飾を続けて記述し、細かく条件を加えられる。

 

INSERT文

INSERT INTO テーブル名 (列名1,列名2,・・・)
VALUES (値1,値2,・・・)

基本的には、1行目にINSERT INTO、2行目にはVALUES句を記述する。

1行目のINSERT INTOには、データを追加するテーブル名を記述する。

さらに、その後ろにデータを追加する列名を指定する。

2行目以降には、VALUESを続けて記述し、追加するデータを記述する。

 

・・・次の記事に続きます

mei98.hatenablog.com

C言語 ポインタについて学んだことを書き起こす その①

初投稿です。

「学んだことはブログなどに書き込んでアウトプットすると良い」

らしいので試してみます。

 

今回は、C言語のポインタについて学んだことをメモ兼アウトプットします。

学ぶのに使った本は「C言語ポインタ完全制覇(ISBN978-4-7741-9381-6)」

という本です。

 

今回は第一章の内容をメモしていきます。

 

ポインタ型とは

例えば「int型」や「double型」が存在するが、それらから派生して作り出される型。

ポインタ型にさせるためには、型に「*」を付け加える。

そうすることで「intへのポインタ型」「doubleへのポインタ型」へと派生される。

ちなみに*は「間接演算子」と呼ぶ。

 

int iHoge;  //int型
int* pHoge; //intへのポインタ型

 

で、このポインタ型には値として、メモリのアドレスを入れることができる。

 

例えば、iHogeのアドレスをpHogeに入れたいときには、変数に「&」を付け加える。

&は「アドレス演算子」と呼び、変数のアドレスを表示させるためのもの。

iHoge = 10;
pHoge = &iHoge; //iHogeのアドレスを、pHogeに代入

↓ このようにしたときのイメージ

ポインタのイメージ

このときの状況は、「pHogeは、iHogeを指している」と言うらしい。

 

次のように、ポインタ型に対して*をつけることで

指した先の値を表示することができる。

printf("%p",(void*)pHoge); //「0x01234」が表示される
printf("%d",*pHoge); //「10」が表示される

 

添字演算子

配列の要素を参照する [ ] を「添字演算子」と呼ぶ。

 

ちなみに、宣言のときの *[ ] と、式の中に現れる *[ ] は全く別もの。

と、本の筆者は述べてました。

この添字演算子も、ポインタと似たような性質を持っていますが

詳細は後で書きます。

 

ポインタ演算

C言語には、ポインタ演算という独特な機能がある。

 

次のようにしたとき、例えば「0x01234」が出力されるとする

int iHoge = 10;
int* pHoge = &iHoge; //iHogeのアドレスを、pHogeに代入

printf("%p\n",(void*)pHoge);

 

次に、pHogeに対して1加算すると、型のサイズ分だけアドレスが増加する。

「0x01234」の4バイト先なので、出力は「0x01238」になる。

※今回の例ではint型は4バイトとする

iHoge += 1; 
printf("%p\n",(void*)pHoge);

 

ヌルポインタ

「ヌルポインタ」とは何も指していないことが保証されるポインタのことを言う。

ちなみに一昔前のネットミーム「ぬるぽ」もここから来てるんだとか。

 

・・・話を元に戻して

ヌルポインタを表す定数値として、通常はマクロNULLが使用されるとのこと。

自分の環境のNULLは次のようになってました。

よく見る「NULL」の正体は「(void*)0」でした。

この0という数字は、「ゼロ番地」的な意味合いになるみたいです。

 

C言語では、0という定数は、ポインタとして使う場合ではヌルポインタとして扱われる。

とのことです。

なので次のように、ポインタ型に対して0を代入することができます。

ただし0以外の値はただのint型になるので、環境によっては警告が出ます。

*hoge = 0; // コンパイラがNULLポインタとして読み替える。
*hoge = 3; // 環境によっては警告が出る

 

ただ「単に定数0を渡しているプログラムは移植性が低い」と筆者は述べてました。

ヌルポインタを表現したいときは0ではなくNULLを代入すべき、と解釈しました。

 

ヌル(NULL)とナル(\0)の違い

・ヌルポインタ

 ポインタ変数が、有効なメモリ領域を指し示していない場合に使用される。

  

・ナル

 文字列の終端を示す時に使用される。

 

よくある間違いとして、文字列の終端させるためにNULLを使うのは間違い。

hoge[len] = NULL; //間違い

 

配列

次の「例1」と「例2」では、同じことをしている。

int iHoge[5] = { 0 , 1 , 2 , 3 , 4}
int* pointer;
int i;

// 例1
for(i = 0; i < 5; i++) {
printf("%d\n", *( p + i ));
}

// 例2
for(i = 0; i < 5; i++) {
printf("%d\n", p[i] );
}

 

どちらも出力は以下のようになる。

0
1
2
3
4

 

まず、添字演算子 [ ] は、宣言と式では全く異なるもの

という前提があるらしい。

 

  • 宣言で使う添字演算子 [ ] は、これが「配列である」ということを表す。
  • 式の中で使う添字演算子 [ ] は、例1にある *(  p + i  ) の簡略記法。

 

という具合。

なので、ポインタ型変数 pointerに配列の先頭アドレスを渡すとき

p = &array[0]

p = array

は、どちらもやっていることは変わらない。

つまり、式の中での

p[ i ]

これは

*( p + i )

を略したもの、ということになるらしい。

シンタックスシュガー。

 

またC言語においては、関数の引数として配列を渡すことができない。

一見配列を渡しているように見えるプログラムでも

実際は、配列の先頭アドレスを渡しているだけになる。

(ということは、引数には配列の要素数も必ず渡さなければ危険ということか・・・)

 

つまりは、次のような関数を作ったとしても

int func1( int a[] )
int func2( int a[10] )

結局値として渡されるのは配列の先頭アドレスなので

int func3( int* a )

このような書き方をしているのと全く一緒。コンパイルによって書き換えられるらしい。

個人的に思ったのは、func1、func2の書き方は、引数として配列を渡してほしい時とか

特定の要素数だけの配列を渡してほしいときに、あえて書く時ぐらいかな?

 

その②に続きます。