個人的リマインド用
比較的軽いやつ
データベースの用語
データベースの中にテーブルを作る(幾つでも作れるよ)
テーブルは表のようになっている(title,body,idとかがある)
行(横)のことをRecord/Row,列(縦)のことをField/Columnという
こういう表を扱う言語をSQL(Structured Query Languageという)
データベースの操作
SQLite起動
sqlite3 [ファイル名]
その後.helpでいろいろ見れるし、
.exitやControl+dで強制終了
データベースに対して操作しないと、ファイルは作られない
テーブル作成
作成
create table posts(テーブル名) ();(例)
テクニック(もしpostsが既にあったらエラーになる)
create table if not exists posts (); こうしたら大丈夫
ちなsqliteでは作成時のコマンドで大文字小文字を区別しない
フィールド設定
create table if not exists posts (
id,
title,
body
);
テーブルを見る
テーブルリスト
.tables
テーブル構成
.schema [テーブル名] テーブル名書かなかったら全てのテーブル
テーブル削除
削除
drop table [テーブル名];
作成同様のテクニック
drop table if exists posts;
テーブルの名前変更・フィールド追加
名称変更
alter table [元名称] rename to [新名称];
フィールド追加
alter table [テーブル名] add column [フィールド名] [型];
レコードの挿入
insert into [テーブル名] (フィールド名, フィールド名) values ('title', 'body1');
sqliteでは文字列は''で囲む
''の中で'を使いたい時は''2個書く
改行したい時はその場で改行すればOK
id integer primary keyに何も挿入しなかったら(nullを入れる場合も)、自動で連番がつく
外部からファイルを扱う
例えばcommands.sqlとかいうファイルを作る(ここにコードを書く)
ファイルの実行(読み取り)
.read commands.sql
コマンドラインから直接読み取る
sqlite3 [ファイル名] < commands.sql
制約について
unique 重複した値を許さない
not null nullを許さない
default 何も値を設定しなかった時のdefault値を指定する
check 値のチェックをする
create table if not exists users (
id integer primary key,
name text not null,
score integer default 10 check (score >= 0),
email text unique
);
selectでのデータの抽出
select * from users; すべてを抽出
select [id, name] from users; フィールドごと抽出
.headers on
select id, name from users; フィールド名とかを上に出してくれる
select id, name as user_name from users; フィールド名変更
横に長くなって見にくい時
.mode line
select * from users; 縦にしてくれる
lineの他にもcsv(,区切り),html(html表記),column(幅を揃えて見やすくする)
whereで条件指定
60より大きいものを抽出したい時
select * from users where score > 60;
50以上80以下
select * from users where score >= 50 and score <= 80;
select * from users where score between 50 and 80; 上と同じ
名前がtanakaかsatoか
select * from users where name in ('tanaka', 'sato');
nullを抽出
select * from users where score is null; is not nullで逆に
likeで条件指定
まずは完全一致で抽出
select * from users where name = 'Tanaka';
ワイルドカード _任意の1文字 %0文字以上の文字列
satoを曖昧なまま抽出したい
select * from users where name like 's___';
前と後ろはなんでもいいがiを含んでいる
select * from users where name like '%i%';
simizu%を抽出したい
select * from users where name like '%@%' escape '@';
globで条件指定
likeとの違い
大文字小文字を区別する
ワイルドカード _→? %→* [abc]abcのどれか [a-z]aからzのどれか
tかsかで始まる文字列
select * from users where name like '[ts]*';
komiya*を抽出したい
select * from users where name like '*[*]';
並び替え・抽出制限
スコアの小さい順
select * from users order by score;
select * from users where score is not null order by score; nullを外す
select * from users order by score desc; 大きい順になる
抽出制限
上位3件
select * from users order by score desc limit 3;
最初の2件を飛ばして3件
select * from users order by score desc limit 3 offset 2;
select * from users order by score desc limit 2, 3;
viewで抽出条件を保存
create view hiscore as select * from users order by score desc limit 5;
select * from hiscore; 上の条件で抽出できる
viewの削除
drop view if exists hiscore;
簡単な演算
scoreに10づつ足していく
select id, name, score + 10 from users;
文字列の連結は||
select id, 'Name: ' || name, score + 10 from users;
組み込み関数
count 個数を数える
max 最大値を求める
min 最小値を求める
avg 平均を求める
length 文字数がわかる
upper 全て大文字にする
substr(name, 2, 3) nameの2文字目から3文字分を引っ張ってきてくれる
select count(id), max(score), min(score), avg(score) from users;
select name, length(name), upper(name), substr(name, 2, 3) from users;
直近で挿入されたレコードのidをもとめる
select last_insert_rowid();
select random() 乱数を返す
ランダムな人を当選させる
select * from users order by random() limit 1;
group byで集計
データではteamA,B,Cに分けられている状態
チームごとの平均スコアを出す
select team, avg(score) from users group by team;
その中でも平均スコアが50を超えているものを抽出(having)
select team, avg(score) from users group by team having avg(score) > 50;
whereを使うと集計前を抽出してしまう
重複しているデータを除外する(distinct)
select distinct team from users;
caseで値を設定
スコアを元にランク付け
select
id,name,score
case
when score > 70 then 'A'
when score > 50 then 'B'
else 'C'
end as rank
from users;
チームごとにマスコットを与える
select
id,name,team
case team
when 'team-A' then 'Bears'
when 'team-B' then 'Panda'
when 'team-C' then 'Python'
else 'nobody'
end as mascot
from users;
レコードの更新と削除
scoreが60より小さい人のscoreを0にして、名前の前に印をつける
update users set score = 0, name = '*' || name where score < 60;
select * from users;
全てのレコードを削除
delete from users;
scoreが0の人のレコードを削除
delete from users where score = 0;
select * from users;
一連の処理をまとめて
tanakaから10点引いて、satoに10点足す
begin transaction;
update users set score = score - 10 where name = 'tanaka';
update users set score = score + 10 where name = 'sato';
commit;
間の処理はまとめて行われる
commitをrollbackに変えれば、処理は行われなくなる
トリガー
誰かの点が100点を超えたら、messageテーブルにメッセージが送信されるように
create table messages (message);
create trigger new_winner update of score on users when new(old).score > 100
begin
insert into messages (messages) values (
'name: ' || new.name ||
'' || old.score ||
' → ' || new.score
);
end;
.schema トリガーの構成を見る
drop trigger new_winner; トリガーを消す
indexの設定
索引が高速になるが、挿入や更新の際重くなる
create index score_index on users(score);
create unique index name_index on users(name); unique制約と同じ
.indices [テーブル名] indexの一覧を見る
.schema [テーブル名] indexの構造を見る
drop index if exists score_index; indexを消す
日時の取り扱い
データ型はないから、日時を表す数字や文字列を管理して、それに関数を組み合わせてやりくりする
select datetime('now', '+09:00:00'); 日本の現在の時間を返す
date()日付だけ取得、time()時間だけ取得、strftime()指定のフォーマットで取得
2023年3月1日に対して、+3ヶ月して、その月の初めをとり、されから1日引く
select date('2023-03-01', '+3 months', 'start of month', '-1 day');
create tableした時に、自動的にレコードの作成日時を入れる
//table追加//
created datetime(こんな型はないがわかりやすく) default date('new', '+09:00:00')
複数のテーブルからデータを引っ張ってくる
create table posts (
id integer primary key,
title text,
body text
)
insert into posts (id, title, body) values (1, 't1', 'b1');
insert into posts (id, title, body) values (2, 't2', 'b2');
create table comments (
id integer primary key,
post_id integer,
comment text
)
insert into posts (id, post_id, comment) values (1, '1', 'c1');
insert into posts (id, post_id, comment) values (2, '1', 'c2');
内部結合
上例で、postsのidとcommentsのpost_idを紐づけた時、両方にデータがあるものだけを結合する
(今回で言うとコメントがついているものだけもってくる)
select * from posts inner(省略可) join comments on posts.id = comments.post_id;
↓上から特定のカラムだけ持ってくる
select posts.id, title, comment from posts join comments on posts.id = comments.post_id;
外部結合
どちらかにしかないものを引っ張ってくる
SQLiteでは左側にしかないものを持ってくるleft outer joinしかない
select posts.id, title, comment from posts left join comments on posts.id = comments.post_id;
rowid
テーブル作ると勝手にrowid(連番)が設定される
id integer primary keyはrowidを指し示している
・問題点
例えば三番目を消して新しいものを追加した場合、それが3になってしまう
4から始めたい時はテーブル作成時、idのとこにautoincrementを追加
データベースの内容をSQLで出力
.output [出力先]
.dump [テーブル名]
CSVファイル
難しいからわからない時は別途確認
.mode csv
.import [ファイル名.csv] [どのテーブルに読み込むか]
データ型について
integer(整数), real(浮動小数点数), text(文字列), blob(そのままデータを保存), null(何もない)
sqliteは型制約が緩い
create table if not exists posts (
id integer primary key(主キー,必ず整数に),
title text,
body text
);