SQLiteの研究ノート(6)

免責事項:この記事はブロガーオリジナル記事です、ソースを明記してください。https://blog.csdn.net/qq_38182125/article/details/89453107

アウトライン

次のように、この記事の構造は次のとおりです。

  • ビュー(ビュー)
  • インデックス(指数)
  • トリガー(トリガー)
  • トランザクション(トランザクション)

ビュー

ビュー(ビュー)または仮想テーブルは、また、その内容が他のテーブルの結果から導出され、誘導されたテーブルと呼ばれます。ビューは、基本表のように見えますが、ベーステーブルの内容が長持ちし、コンテンツビューが使用している場合は、動的に生成されるということです。ので、それは、ベーステーブルではありませんが、ビューの構文を作成し、次のとおりです。

CREATE VIEW name AS select-stmt;

定義されたセレクトのstmtによって規定されている名前で指定されたビューの名前。最終的に生成されたビューは、ベーステーブル名の名前のように見えます。我々は、次の理由でビューを使用する傾向があります:

  • SQL文を再利用します。
  • 複雑なSQL操作を簡素化します。クエリを記述した後、あなたは簡単にその基本的なクエリの詳細を知らなくても、それを再利用することができます。
  • 代わりに、テーブルを使用して、テーブル全体の一部。
  • データを保護します。あなたは、特定のテーブルの一部で、全体ではなく、テーブルへのアクセスにアクセスするための権限を付与することができます。
  • データ形式とプレゼンテーションを変更します。テーブルの異なるビューは、基礎となるデータやフォーマットを表して戻してもよいです。

次の例では、データの検索を見てみましょう。

SELECT cust_name, cust_contact 
FROM Customers, Orders, OrderItems 
WHERE Customers.cust_id = Orders.cust_id 
AND OrderItems.order_num = Orders.order_num 
AND prod_id = 'RGAN01';

この例では、3つのテーブルを結合し、の「RGAN01」としてPROD_ID顧客情報を取得します。我々は、顧客情報の「DLL01」としてPROD_ID取得する必要がある場合や、コマンドの長いリストの一番上に、それは再び、この時間は、私たちは一緒に再利用可能な部品使用の可能性を視野に入れて検討することができ、再入力する必要がありました。次のように:

CREATE VIEW ProductCustomers AS 
SELECT cust_name, cust_contact, prod_id  
FROM Customers, Orders, OrderItems 
WHERE Customers.cust_id = Orders.cust_id 
AND OrderItems.order_num = Orders.order_num;

ビューを作成した後、次のように、私たちは、このビューを使用することができます。

入力:

SELECT cust_name, cust_contact 
FROM ProductCustomers 
WHERE prod_id = 'RGAN01';

出力:

cust_name   cust_contact
----------  ------------------
Fun4All     Denise L. Stephens
The Toy St  Kim Howard

ビューでは、我々はいくつかのSQLステートメントを省略することができ、我々は顧客が「DLL01」として、あなたはSQL文の前と同じくらいの入力を必要としないPROD_ID照会したい場合は、その再利用性を向上させます。

注意:
SQLiteの更新可能なビューがサポートされていない、つまりのみ検索でビューを使用してSQLiteの。
ビューを作成し、その再利用性を考慮したときにビューを作成しようとする必要があり、特定のデータにバインドされていないことが多い良い選択です。

ビューを削除する必要がある場合は、単に次のコマンドを実行します。

DROP VIEW ProductsCustomers;

第二に、インデックス

インデックス(指数)は、クエリをスピードアップするために使用される一定の条件の下での構造です。既存の検索は次のとおりです。

SELECT cust_name, cust_contact 
FROM Customers 
WHERE cust_id = '100000002';

通常の状況下では、データベースシーケンシャルスキャン、すべての行の検索テーブル内の一つ一つは、コンプライアンスは「十億二」=出力文をCUST_ID。Customersテーブルが非常に大きい場合でも、そのデータを取得するこの方法は、その後、我々はSQLiteのは、Bツリー索引の使用を基礎となる、インデックス検索速度の使用を加速する方法を検討することができ、非常に非効率的になります。

次のようにインデックスコマンドを作成します。

CREATE INDEX [UNIQUE] index_name ON table_name (columns);

INDEX_NAMEはtable_nameは、インデックステーブルの名前であるフィールドを含むインデックス変数の名前であり、変数の列は、カンマ区切りのフィールドまたはフィールドです。

キーワードUNIQUEを使用する場合は、インデックスの制約を追加します、インデックス内のすべての値は一意である必要があります。これは、インデックスにないのみ適用され、また、インデックスフィールドに適用されます。例としては、次のとおりです:

sqlite> CREATE TABLE Foo(a text, b text);
sqlite> CREATE UNIQUE INDEX Foo_idx ON Foo(a,b);
sqlite> INSERT INTO Foo VALUES('unique', 'value');
sqlite> INSERT INTO Foo VALUES('unique', 'value1');
sqlite> INSERT INTO Foo VALUES('unique', 'value');
Error: UNIQUE constraint failed: Foo.a, Foo.b

私たちは、とき共同フィールド値の重複、それはエラーになり、エラーメッセージから見ることができます。あなたは、インデックスを削除したい場合は、DROP INDEXコマンドを使用します。

DROP INDEX Foo_idx;

注意:

  • インデックスは、当社の検索速度をスピードアップすることができますが、インデックスデータがマルチテーブルインデックス内のすべてのフィールドが作成されている場合は特に、収納スペースの多くを取るために持っているかもしれないが、テーブルのサイズが2倍にすることができます。
  • 考慮すべきもう一つの問題は、インデックスのメンテナンスです。INSERT、UPDATEと、テーブルを変更するだけで、操作を削除すると、データベースは、挿入、更新および動作速度等がある場合、指標を低減することができるインデックスに対応する修正する必要があります。
  • 最後に、ときにインデックスに複数の列を定義する(例えば、州や都市)。状態プラス都市に順番を並べ替えるときに、このインデックスにのみ有効です。あなたが街でソートしたい場合は、このインデックスは有用ではありません。

1.インデックス

SQLiteは、インデックスを使用するかどうかを決定するためにいくつかの特定の条件があります。次の式はWHERE句に表示されます。SQLiteは、単一のインデックスフィールドを使用します。

column { = | > | >= | <= | < } expression
expression { = | > | >= | <= | < } column
column IN (expression-list)
column IN (subquery)

以下のいくつかの例は次のようにテーブルが定義されていることを前提と、例示します:

CREATE TABLE foo (a,b,c,d);

この時点で、インデックスは、次のフィールドの多くを作成します。

create index foo_idx on foo(a,b,c,d);

今すぐ検索し、次のとおりです。

SELECT * FROM foo WHERE a=1 AND b=2 AND d=3;

唯一の第一及び第二の条件は、インデックスを使用します。第三の条件を使用しない理由は、ギャップdを狭くするために、Cを使用するいかなる条件ではありません。WHERE句を見つけることができないまで、SQLiteは、その上に複数フィールドインデックスにフィールドの左側から始まったインテリジェントフィールドを使用するときに2番目のフィールドに移動し、その後、クエリフィールドを使用し、右の使用に委ね、そして有効な条件。

SELECT * FROM foo WHERE a>1 AND b=2 AND c=3 AND d=4;

SQLiteのインデックススキャンは、式a> 1インデックスフィールドは、右端と呼ばれるフィールド上で行われます、それは不平等を使用しているため同様に、次の文は、B> 2で停止します。

SELECT * FROM foo WHERE a=1 AND b>2 AND c=3 AND d=4;

すべてのすべてで、達成することができる改良された性能を確保するための十分な理由を持っている必要がありますインデックスを作成するそれ以外の場合は、負の最適化があるかもしれません。


第三に、フリップフロップ

特定のデータベース・アクティビティが発生したときにトリガー(引き金)が自動的に実行されます。これは、特定のテーブルのINSERT、UPDATE、DELETEおよび(または組み合わせ)関連する動作にトリガすることができます。一般的な次のようにトリガコマンドを作成するには:

CREATE [TEMP|TEMPORARY] TRIGGER trigger_name 
[BEFORE|AFTER] [INSERT|DELETE|UPDATE|UPDATE OF columns] ON table_name 
BEGIN 
	-- trigger logic goes here...
END;

トリガーは、名前、行動やテーブル定義です。特定のイベントが発生した場合、トリガは、これらのコマンドを開始するための責任があり、SQLの一連のコマンドを実施します。操作は事件発生後または前に実行される前または後にまたこれらのキーワードを指定することができます。前記テーブルにUPDATEトリガーを作成する列または複数の指定フィールドをすることができます。

ここでは、トリガーのいくつかの一般的な用途は以下のとおりです。

  • データの整合性を確認してください。例えばINSERTやUPDATE操作状態のすべて大文字に変換。
  • 他のテーブルでの活動の実施に関するテーブルの変更に基づいています。たとえば、行が更新または削除するたびに監査証跡レコードは、ログテーブルに書き込まれます。
  • 確認し、ロールバックするために必要な追加データ。たとえば、あなたがブロックインサートを超えた場合、お客様は、利用可能な資金の限度を超えないことを確認します。
  • タイムスタンプ値または計算列を更新します。

以下は、トリガーの簡単な例です:

CREATE TABLE Company
(
	id      integer PRIMARY KEY,
	name    text NOT NULL,
	address text NOT NULL
);

CREATE TABLE log(
	emp_id integer, 
	emp_date text
);

二つのテーブル、記録動作のためのテーブルベースとテーブル会社のログを作成します。次に、トリガーを作成します。

CREATE TRIGGER log_trigger AFTER INSERT ON Company 
BEGIN 
	INSERT INTO log VALUES(new.id, datetime('now'));
END;

我々は次のいくつかの挿入データの検証をトリガー効果を作成しようとした後:

INSERT INTO Company VALUES(null, 'Baidu', 'Beijing');
INSERT INTO Company VALUES(null, 'Alibaba', 'HangZhou');
INSERT INTO Company VALUES(null, 'Tencent', 'ShenZhen');

SELECT * FROM log;

emp_id      emp_date
----------  -------------------
1           2019-04-23 01:18:30
2           2019-04-23 01:18:45
3           2019-04-23 01:18:47

見ることができ、我々は、対応するテーブルにログ情報を保存するためのトリガ挿入操作を経由して時間を記録することができます。

注:
他のDBMSで、各ステートメントのトリガーのためにサポートされ、各行のトリガをサポートすることができます。しかし、それぞれの行トリガーのための唯一のSQLiteのサポートは、つまり、それぞれの影響を受けた行の動作文は、彼が一度トリガーされたとき。

あなたはトリガーを一覧表示したい場合は、sqlite_master助けることができます。

SELECT name FROM sqlite_master WHERE type = 'trigger';

name
-----------
log_trigger

同じように、単純なトリガーを削除します。

DROP TRIGGER log_trigger;

第四に、トランザクション

SQLiteのサポートサービスの操作、トランザクション操作をサポートするには、データベースは、4つのプロパティのACIDトランザクションをサポートしなければならないことを意味します。

プロパティ 説明
アトミック(不可分) 原子性は、すべての成功のいずれか含まトランザクション内のすべての操作を指し、またはすべての操作が成功した場合、彼らはそれ以外の場合は、データベースへの影響を持つことができない、データベースへのアプリケーションのトランザクションを完了しなければならない、つまり、ロールバックに失敗します
一貫性(Consustency) 一貫性は、それが一貫性のある状態にする必要があります前に、トランザクションの実行と実施後、ある、別の一貫した状態にある一貫した状態からデータベースを変換する必要がありますトランザクションを指し、
絶縁(アイソレーション) 分離複数のユーザこのようなテーブルを用いて動作としてデータベースへの同時アクセスを、各ユーザのトランザクションのデータベースのオープンは、他の同時複数のトランザクション間の分離のために、しっかり干渉できない場合
永続性(耐久性) 持続性は、一度トランザクションがコミットされることを意味し、その後、データベース内のデータに変化しても、データベースシステムの障害が発生した場合にコミットされたトランザクションの営業損失はなかった、永久的なもの

1.コマンド・総務

開始、コミットやロールバック:総務は三つのコマンドによって制御されています。開いているトランザクションを開始し、すべての操作をキャンセルした後に開始することができ、それは、接続がキャンセルされる前に終了した場合にコミットを発行しませんでした。トランザクションをコミット実行されるすべての操作をコミット開始しました。ロールバックはすべてが開始した後の操作を復元することです。例えば:

sqlite> begin;
sqlite> DELETE FROM Products;
sqlite> rollback;
sqlite> SELECT count(*) FROM Products;

count(*)
----------
9

この例では、製品内のすべてのデータを削除し、そのデータがまだ製品が存在する再クエリロールバックで行われたトランザクションを開きます。

デフォルトでは、トランザクションからの(自動コミットモード)への各SQL文でSQLiteのことで。言い換えれば、SQLiteのデフォルトでは、個々のSQLステートメントは失敗したコマンドがロールバックされ、この動作モードは、自動として知られている、すべての成功したコマンドが自動的に提出される場合には、トランザクションのコミット/ロールバック...始めていコミットモード。

2.予約されたスポットを使用します

SQLiteのサポートセーブポイントとリリース受注は、仕事が複数のステートメントは、セーブポイントに戻ることができますロールバック、セーブポイントを設定することができ備えます。次のようにセーブポイントコマンドは作成します。

savepoint savepoint_name;

バックどこかにフォールする必要性を認識した場合、トランザクション全体をロールバックしていない、ロールバックは、次のコマンドを使用することができます。

rollback [transaction] to savepoint_name;

すべての最初の使用の下に表示する例では、のは、その後の比較のために、Customersテーブルの情報を見てみましょう:

sqlite> select cust_id, cust_name from Customers;
cust_id     cust_name
----------  ------------
1000000001  Village Toys
1000000002  Kids Place
1000000003  Fun4All
1000000004  Fun4All
1000000005  The Toy Stor

その後、我々は、トランザクションが保持ポイントが含まれて実行します。

begin;
INSERT INTO Customers(cust_id, cust_name) VALUES('1000000010', 'Toys Emporium');
savepoint one;
INSERT INTO  Customers(cust_id, cust_name) VALUES('1000000008', 'Toys Moyu');
INSERT INTO  Customers(cust_id, cust_name) VALUES('1000000007', 'Toys JKLove');
rollback to one;
commit;

トランザクションの実装が戻って一点に実際にこのデータだけ十億十に挿入CUST_IDされ、この予約を、圧延される理論的に後、のは、そのようなことで、クエリかどうかを見てみましょう:

sqlite> select cust_id, cust_name from Customers;
cust_id     cust_name
----------  ------------
1000000001  Village Toys
1000000002  Kids Place
1000000003  Fun4All
1000000004  Fun4All
1000000005  The Toy Stor
1000000010  Toys Emporiu

あなたは本当に大まかにしかセーブポイントの使用で新たに挿入された文を、見ることができます。

保持点を解除するコマンドを放出する、放出は、例えば、次のトランザクションがエラーを生成する場合、決定するために使用されないセーブポイントで実行される必要があります。

begin;
INSERT INTO Customers(cust_id, cust_name) VALUES('1000000010', 'Toys Emporium');
savepoint one;
INSERT INTO  Customers(cust_id, cust_name) VALUES('1000000008', 'Toys Moyu');
INSERT INTO  Customers(cust_id, cust_name) VALUES('1000000007', 'Toys JKLove');
release one;
rollback to one;
commit;

Error: no such savepoint: one

後者の場合、最初の1がリリースされる1つのポイントの使用に予約されます、それは次のロールバック文が一つのケースで見つけることができない原因になります。

3.紛争解決

ときに制約違反がトランザクションの終了になります。(データベースのほとんどを処理している)すべての廃止前に修正するだけの結果の終了に加えて、SQLiteは以下のオプションが用意されています。

戦術 説明
置き換えます ユニーク制約違反が、SQLiteのは、このレコードの違反につながる場合には、新しいレコードや修正、代替を挿入するために、削除、SQLiteのは継続、違反がNOT NULL制約で、フィールドがデフォルトでない場合は、SQLiteのアプリケーションは、戦略を中止します
無視します 制約違反が発生した場合、SQLiteのコマンドは実行を継続することを可能にする、制約違反は同じままですが、前と後にそれがレコードを変更していきます
失敗します 制約違反が発生した場合に制約違反がレコードを変更されている前に、SQLiteの終了コマンドは、しかし回復しません
アボート 制約違反が発生した場合、SQLiteのコマンドを実行すると、すべての変更を行い、コマンドを終了さを復元します。SQLiteは、デフォルトではすべての操作のソリューションを中止されます
ロールバック 制約違反が発生すると、SQLiteはロールバックを実行する - 現在のコマンドとトランザクション全体を終了します

次のように紛争解決の構文は次のとおりです。

INSERT OR resolution INTO table_name (column_list) VALUES (value_list);
UPDATE OR resolution table_name SET (value_list) WHERE predicate;

それの典型的な使用を行うために、例を次のように、我々は次の表を想定しています:

CREATE TABLE test(id integer PRIMARY KEY);
SELECT count(*) FROM test;

count(*)
----------
412

これは、412に、データ、データ1の412行の合計を含んでいます。ここで、次の更新を行います。

UPDATE test SET id=800-id;
Error: UNIQUE constraint failed: test.id

私たちは、UPDATE文が最初の388件のレコードを更新するとき、それはidは800から388 = 412に更新しますが、テストで412既に存在しているため、コマンドが終了し表示されますので、それは、一意性制約に違反して見ることができます。以前の分析によると、我々はそれが377の成功した更新レコードの前にキャンセルされますと言うことですデフォルトの実行中止戦略、であることを知っています。

我々は正常に更新することができます377前のレコードを保持したい場合は、私たちは、次のコマンドを入力することができます。

UPDATE OR FAIL test SET id=800-id;

失敗ポリシーを設定することで、あなたは保存377のレコードの前を変更することができます。


参照

"SQLiteのDefinitive Guideの"

  • 第4章sqliteの高度なSQL

「SQLを知らなければならないだろう」

  • ビューを使用したレッスン18
  • レッスン20トランザクション管理
  • レッスン22の高度なSQLの機能

私は〜あなたを助けるために、この記事を願っています

おすすめ

転載: blog.csdn.net/qq_38182125/article/details/89453107