LoginSignup
1
1

More than 1 year has passed since last update.

3/31 SQLite入門

Posted at

個人的リマインド用

比較的軽いやつ

データベースの用語

データベースの中にテーブルを作る(幾つでも作れるよ)
テーブルは表のようになっている(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
);
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1