2016年1月31日日曜日

[SQLite]複数のデータベースを結合する

SQLiteでは、1つのDBがファイルとなります。
他のDBファイルにあるデータと結合する場合は、ATTACH DATABASEで取り込んでから結合する。

簡単なdbを二つ作ってみます。
C:\Users\test>sqlite3 data1.db
SQLite version 3.10.2 2016-01-20 15:27:19
Enter ".help" for usage hints.
sqlite> create table table1 (id, value);
sqlite> insert into table1 (id, value) values(1, 'a1');
sqlite> insert into table1 (id, value) values(2, 'a2');
sqlite> insert into table1 (id, value) values(3, 'a3');
sqlite> .quit

C:\Users\test>sqlite3 data2.db
SQLite version 3.10.2 2016-01-20 15:27:19
Enter ".help" for usage hints.
sqlite> create table table2 (id, value);
sqlite> insert into table2 (id, value) values(1, 'b1');
sqlite> insert into table2 (id, value) values(2, 'b2');
sqlite> insert into table2 (id, value) values(3, 'b3');
sqlite> .quit


こんな状態です
data1.db > table1
id          value
----------  ----------
1           a1
2           a2
3           a3

data2.db table2
id          value
----------  ----------
1           b1
2           b2
3           b3

別々のファイルのid列を結合した結果を表示したい。
そんな時は、データベースをATTACHすればよいです。

DBに接続した直後に .databases を実行すると現在接続できているdbが表示されます。
C:\Users\test>sqlite3 data1.db
SQLite version 3.10.2 2016-01-20 15:27:19
Enter ".help" for usage hints.
sqlite> .databases
seq  name             file

---  ---------------  -----------------------

0    main             C:\Users\test\data1.db

ATTACH DATABASE [filePath] AS databaseName
ATTACH [filePath] AS databaseName

で、DBの追加ができます
sqlite> ATTACH "C:\Users\test\data2.db" AS db2;
sqlite> .databases
seq  name             file

---  ---------------  -------------------------

0    main             C:\Users\test\data1.db

2    db2              C:\Users\test\data2.db

あとは、db名.table名.column名で指定すればよいだけですね

sqlite> SELECT main.table1.id, main.table1.value, db2.table2.value
   ...> FROM main.table1
   ...> INNER JOIN db2.table2
   ...> ON main.table1.id = db2.table2.id;
id          value       value
----------  ----------  ----------
1           a1          b1
2           a2          b2
3           a3          b3




using System;
using System.Data.SQLite;
using System.Windows.Forms;

namespace SampleCode
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (SQLiteConnection con = new SQLiteConnection("Data Source=data1.db"))
                {   
                    con.Open();

                    // data2.dbをAttachする
                    using (SQLiteCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = "ATTACH [data2.db] AS db2;";

                        cmd.ExecuteNonQuery();
                    }

                    using (SQLiteCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = "SELECT main.table1.id, main.table1.value, db2.table2.value " +
                                          "FROM main.table1 " +
                                          "INNER JOIN db2.table2 " +
                                          "ON main.table1.id = db2.table2.id;";

                        SQLiteDataReader reader = cmd.ExecuteReader();

                        while (reader.Read())
                        {
                            string data = string.Format("{0}\t{1}\t{2}", reader[0].ToString(), reader[1].ToString(), reader[2].ToString());
                            Console.WriteLine(data);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}



注意点として、ATTACH する時 ダブルクォートかブラケットで囲まないとエラーになります。
OK "ATTACH \"data2.db\" AS db2;";
OK "ATTACH [data2.db] AS db2;";
NG "ATTACH data2.db AS db2;";

database schema has changed
no such column: data2.db

SQLiteだと、ロックがファイル単位でロックがかかるので
頻繁に更新のあるテーブルは分けて、別ファイルで結合するのがよさそうですね。

ちなみに、DETACHで現在の接続から切り離す事ができます。
DETACH DATABASE [databaseName]
DETACH [databaseName]

0 件のコメント:

コメントを投稿