2016年5月29日日曜日

[SQL Server]SqlDataReaderを使ってデータを取得


・App.config


  
    
  


・プログラム
using System;
using System.Configuration;
using System.Data.SqlClient;

namespace SqlServerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
            
            using(SqlConnection con = new SqlConnection(connectionString)){
                con.Open();

                using (SqlCommand command = con.CreateCommand())
                {
                    string sql = "SELECT TOP 10 [BusinessEntityID], [FirstName] " +
                                 "FROM [Person].[Person];";
                    command.CommandText = sql;

                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            string[] data = new string[] { reader["BusinessEntityID"].ToString(), 
                                                          reader["FirstName"].ToString() };
                            Console.WriteLine(string.Join("\t", data));
                        }
                    }
                }
            }
        }
    }
}

[SQL Server]接続、切断

・ちょっと確認したい用途など、手っ取り早く行うなら接続文字列をハードコード。

using System.Data.SqlClient;

namespace SqlServerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString = @"Data Source=[ServerName];Initial Catalog=[DatabaseName];User Id=[UserId];Password=[Password];";
            SqlConnection con = new SqlConnection(connectionString);
            con.Open();
            con.Close();
        }
    }
}

[ServerName]は、Expressのデフォルトなら PC名\SQLEXPRESS
[DatabaseName]は、AdventureWorks2012を入れたのであれば AdventureWorks2012
あとは、接続用のUserIdやらパスワードを指定すればよいです。


・接続文字列を、App.configにまとめる。
□App.config


  
    
  


□プログラム
using System.Data.SqlClient;
using System.Configuration;

namespace SqlServerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
            SqlConnection con = new SqlConnection(connectionString);
            con.Open();
            con.Close();
        }
    }
}

System.Data.Configurationは参照に追加する。
その上で、usingする。


開発用と本番環境があって簡単に使い分けたいのであれば
App.configに二つ作成して、呼び分けるのでもよいかもですね。
using System.Data.SqlClient;
using System.Configuration;

namespace SqlServerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string key = string.Empty;

#if DEBUG 
            key = "ConnectionStringDevelopment";
#else
            key = "ConnectionStringProduction";
#endif

            string connectionString = ConfigurationManager.ConnectionStrings[key].ConnectionString;
            SqlConnection con = new SqlConnection(connectionString);
            con.Open();
            con.Close();
        }
    }
}

2016年5月28日土曜日

[SQL Server]SQL Serverで遊ぶ前にサンプルデータベースを準備

ひとまず、SQL Server 2014 Expressをインストール
インストール手順等は、検索していれてくださいな。

せっかくいれても、データがないとつまらないので、サンプルデータベースを用意してみます。

方法 : サンプル データベースをインストールする


上記サイト(msdnのページ)で説明があります。
AdventureWorksを入れてみました。



「CodePlex Webサイト」に飛びます。



「AdventureWorks for SQL Server 2012」に飛びます



一番下の「AdventureWorks2012_Data.zip」をクリック
解凍すると中身はこんな感じ




これを SQL ServerのDataフォルダに配置。
(C:\Program Files\Microsoft SQL Server\MSSQL12.SQLEXPRESS\MSSQL\DATA)




データを追加します。
データベース→右クリック→アタッチ




追加をクリック




AdventureWorks2012_Data.mdfを選択→OK



特にエラーもでていないので、OK




これで追加されました。




これを使って遊んでみます。


スキーマについては、AdventureWorks2008 Schema で検索して見つかるものを参照するとよいと思います。
https://www.google.co.jp/search?q=adventureWorks2008&espv=2&biw=1163&bih=540&source=lnms&tbm=isch&sa=X&ved=0ahUKEwj6u6-akv7MAhVLm5QKHTWfBUwQ_AUIBigB#tbm=isch&q=adventureWorks2008+schema&imgrc=hCx_dwpvVqGmlM%3A

・2012用が見当たらない
・そもそも大本がどこかわからない

ということで画像検索で探してみてください。

SQL Serverメモ

[SQL Server]SQL Serverで遊ぶ前にサンプルデータベースを準備
[SQL Server]接続、切断

□SELECT
[SQL Server]SqlDataReaderを使ってデータを取得

2016年2月1日月曜日

[SQLite]文字数制約

文字数の制約をつけたい。
ひとまず、型の後ろにカッコつけて数字かけばいいのかな?

using System;
using System.Data.SQLite;

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

                    using (SQLiteCommand cmd = con.CreateCommand())
                    {

                        cmd.CommandText = "CREATE TABLE [Sample] (" +
                                          "[data]  TEXT(5) NOT NULL" +
                                          ");";
                        cmd.ExecuteNonQuery();

                        cmd.CommandText = "INSERT INTO [Sample] ([name]) VALUES('123456');";
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

あら・・・怒られない。
そもそも、文字数制限をかけれるような話をみたことないもんなぁ。

じゃ、別の方法で行ってみます。
cmd.CommandText = "CREATE TABLE [Sample] (" +
                                          "[data]  TEXT NOT NULL CHECK(LENGTH([data]) <= 5)" +
                                          ");";
怒られた。
constraint failed
CHECK constraint failed: Sample

[SQLite]テーブルが作られてなければ作成する

すでにテーブルが存在しているのに作成してしうとエラーになります。
using System;
using System.Data.SQLite;

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

                    using (SQLiteCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = "CREATE TABLE [Sample](" +
                                          "[name]  TEXT NOT NULL" +
                                          ");";
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

SQL logic error or missing database
table [Sample] already exists

そこで、存在していない場合のみ作成したい時は、
他のDBにもあるように、IF NOT EXISTSをつければよい
cmd.CommandText = "CREATE TABLE IF NOT EXISTS [Sample] (" +
                                      "[name]  TEXT NOT NULL" +
                                      ");";

これなら問題無し。

[SQLite]Unique制約で大文字小文字を同じ物と判定する方法

例えば、このブログのタグもそうですが、SQLiteもSQLITEもsqliteも一つのものとして判断してほしい場合があると思います。

そこでUniqueキー制約をつけてみると・・・
using System;
using System.Data;
using System.Data.SQLite;

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

                    using (SQLiteCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = "CREATE TABLE [Blog](" +
                                          "[tag]  TEXT    NOT NULL, " +
                                          "UNIQUE([tag])" +
                                          ");";
                        cmd.ExecuteNonQuery();

                        cmd.CommandText = "INSERT INTO [Blog] ([tag]) VALUES('SQLite');";
                        cmd.ExecuteNonQuery();

                        cmd.CommandText = "INSERT INTO [Blog] ([tag]) VALUES('SQLITE');";
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}
問題なく入ります。
大文字と小文字を別物として判断しているからです。

そこで、大文字小文字を区別してほしくない列にCOLLATE NOCASEをつけてみます。
using System;
using System.Data;
using System.Data.SQLite;

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

                    using (SQLiteCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = "CREATE TABLE [Blog](" +
                                          "[tag]  TEXT    NOT NULL, " +
                                          "UNIQUE([tag] COLLATE NOCASE)" +
                                          ");";
                        cmd.ExecuteNonQuery();

                        cmd.CommandText = "INSERT INTO [Blog] ([tag]) VALUES('SQLite');";
                        cmd.ExecuteNonQuery();

                        cmd.CommandText = "INSERT INTO [Blog] ([tag]) VALUES('SQLITE');";
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

エラーがでるようになりました。
constraint failed
UNIQUE constraint failed: Blog.tag


もちろん、PRIMARY KEYであっても同じことです。
cmd.CommandText = "CREATE TABLE [Blog](" +
                                        "[tag]  TEXT , " +
                                        "PRIMARY KEY([tag] COLLATE NOCASE)" +
                                        ");";

uniqueじゃないと怒ってくれます。
constraint failed
UNIQUE constraint failed: Blog.tag

2016年1月31日日曜日

[SQLite]外部キープラグマの確認

SQLiteでは、デフォルトで外部キーチェックが無効となっています。

そもそも外部キー制約が取り入れられたのがVer3.6.19からです。
2009-10-14リリースからですね。
https://www.sqlite.org/oldnews.html

せっかくなので確認してみます。
まずは、デフォルトでの動作確認です。
従業員テーブルと、部署テーブルを定義してから
部署テーブルにデータをいれずに、従業員テーブルにデータを
入れて外部参照エラーを起こさせるシナリオです。
using System;
using System.Data;
using System.Data.SQLite;

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

                    using (SQLiteCommand cmd = con.CreateCommand())
                    {
                        // 部署テーブルの作成
                        cmd.CommandText = "CREATE TABLE [Department](" +
                                          "[id]    INTEGER NOT NULL PRIMARY KEY, " +
                                          "[name]  TEXT    NOT NULL" +
                                          ");";
                        cmd.ExecuteNonQuery();

                        // 従業員テーブルの作成
                        cmd.CommandText = "CREATE TABLE [Employee](" +
                                          "[id]     INTEGER PRIMARY KEY AUTOINCREMENT, " +
                                          "[name]   TEXT    NOT NULL, " +
                                          "[depID]  INTEGER NOT NULL," +
                                          "FOREIGN KEY([id]) REFERENCES [Employee]([depID]) " +
                                          ");";
                        cmd.ExecuteNonQuery();

                        cmd.CommandText = "INSERT INTO [Employee] (name, depID) VALUES('hoge', 100);";
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

何事もなく終了します。
そこで、Foreign Keyプラグマを有効にします。
https://www.sqlite.org/pragma.html#pragma_foreign_keys

下記のように、SQL文として実行することでも有効にできますが・・・
cmd.CommandText = "PRAGMA foreign_keys = ON;";
cmd.ExecuteNonQuery();

接続文字列に指定することもできます。
[SQLite]DB作成および接続


SQLiteConnection con = new SQLiteConnection("Data Source=:memory:;Foreign Keys=True")
これで実行すると、下記のようにエラーになります
SQL logic error or missing database
foreign key mismatch - "Employee" referencing "Employee"

[SQLite]DB作成および接続

◆DBを作成および接続
using System;
using System.Data.SQLite;

namespace SampleCode
{
    class Program
    {
        static void Main(string[] args)
        {
            string filepath = "sample.db";

            try
            {
                using (SQLiteConnection con = new SQLiteConnection("Data Source=" + filepath))
                {
                    con.Open();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

▪️Data Source
オープンしたいデータベースのパスを指定します。
必須項目はこちらのみですが、それ以外に設定できるものは、以下のとおり。

情報は、System.Data.SQLiteのドキュメントです。
SQLiteConnection Classに記載されています。

あらためて説明(めぼしいとこだけ抜粋)
▪️Data Source
file名、:memory:、URI(ver3.7.7以降)に対応している。

:memory: は、ファイルを生成せずにon memoryで処理したい場合に指定。
UNCのパスを使うときは、先頭のスラッシュは2つずつ記載しないといけないそうな。
例としてこんなのが書いてある
(e.g. "\\Network\Share\test.db" would become "\\\\Network\Share\test.db")

この項目だけ必須。
あとは、任意。

Pragmaの設定とかをSQLiteConnectionで設定できます。

--------------------------------------------------------------------------------------------------
▪️Version
バージョン番号。説明は3としか書いてないです・・・
あるサイトにバージョンは3で固定と言った内容をみかけたのですが、どうなんだろう。
Default: 3

--------------------------------------------------------------------------------------------------
▪️UseUTF16Encoding
True→EncodeにUTF16が使われる
False→EncodeにUTF8が使われる
Defaul:False

--------------------------------------------------------------------------------------------------
▪️Cache Size
メモリに保持できる最大ページ数を指定。
保持できる最大メモリ数は、Cache Size x Page Size(bytes)となる
Default:2000

--------------------------------------------------------------------------------------------------
▪️Page Size
ページサイズの指定
Default:1024(byte)

※(メモ)データベースのデータを管理するユニットのサイズ、
データが多くあるのに、ページが小さいと複数のページを読み込まないといけなくなる
逆にたいしたデータがないのに大きいページを設定すると、無駄な読み込みが発生する
SQL Serverあたりは8kbとなっているみたい。
ちなみに、2の累乗の値を設定する必要があるそうな。

--------------------------------------------------------------------------------------------------
▪️Foreign Keys
ver3.6.19から外部参照が使えるようになったのですが
互換性を考慮してか、デフォルトではOFFとなっています。
そのため、この項目をTrueにして接続しないと、外部参照のエラーは発生しません。
(外部参照を設定してもなんでもうけつけてしまう)
Default:false

--------------------------------------------------------------------------------------------------
▪️Password
パスワードを設定することができる。
SQLiteConnectionクラスのChangePasswordメソッドで変更できる

--------------------------------------------------------------------------------------------------
▪️Default IsolationLevel
トランザクション分離レベル
SQLiteConnectionの項目には特に説明はないけど
BeginTransactionの引数で使用できるIsolationLevelの説明だと
SerializableとReadCommittedのみ対応しているみたい。
Default:Serializable

--------------------------------------------------------------------------------------------------
▪️Default Timeout
コマンド実行タイムアウト時間
Default:30[s]

--------------------------------------------------------------------------------------------------
▪️Journal Mode
データの変更時に、一時的に生成されるJournalファイルのモードを設定
Delete, Persist, Off, Truncate, Memory, Walから選べる
Deleteは、コミット後ジャーナルファイルが削除される
Truncate は、削除するかわりにジャーナルサイズを0にする(削除するより早い)
Persistは、コミット後ジャーナルファイルのヘッダーを0に書き換えるだけ(Trancateするより早い)
OFFは、ジャーナルを使わない。ロールバックは使えなくなります。

Memoryは、ジャーナルをファイルではなくメモリ上で行う。
Walは、ログを吐き出した時点でデータファイルに書き込みを行う
Default:Delete

--------------------------------------------------------------------------------------------------
▪️Synchronous
同期の設定。
OFF、Normal、Fullとの3つのモードあり。
OFFの場合、書き込みが完了するか待たずに処理を再開。
NormalとFullは、ディスクへのデータ書き込みを待ってから次の処理に移る。
Fullは、完全に待つが、NormalはFullほどまたない。
Default:Full

※(メモ)下記サイトのPRAGMA default_synchronousの説明がわかりやすかったです
http://net-newbie.com/sqlite/lang.html

--------------------------------------------------------------------------------------------------
▪️Pooling
コネクションプーリング
Default:False

--------------------------------------------------------------------------------------------------
▪️Max Pool Size
コネクションプーリングの最大数
Default:100

[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]

[SQLite]コマンドラインで実行したい

ちょっとした動作の確認をしたい場合にコードを書くのはしんどいのでコマンドラインで確認したくなると思います。

そんな時は、SQLiteのサイトに行き、ダウンロードのページに
http://www.sqlite.org/download.html

Precompiled Binaries for Windowsの項目に
sqlite-tools-win32-x86-3100200.zipのところに「command-line shell program」と説明されているので
これをダウンロードします。




あとは、適当な場所に配置してパスを通すなりすればよいと思います。

2016年1月30日土曜日

[SQLite]C#でSQLiteを使うための準備

まずは、コードをかくまでの準備を行います。
本家サイトにSystem.Data.SQLite.dllがあります。
そちらを持って来ましょう。

本家はこちら→SQLite Home Page
ダウンロードのページに移動すると下記のように書いてあって


System.Data.SQLite.dllは別のページにあるそうです↓
http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki

パッケージの種類については、以下のサイトでとても詳しく書かれているので
そちらを参照していただいた方がわかりやすいと思います。
System.Data.SQLite でどれをインストールするべきか

今回は、32bit .netFrameWork4.0で動かしたかったので
sqlite-netFx40-binary-bundle-x64-2010-1.0.99.0.zip を選択

System.Data.SQlite.dllがまさに欲しかったファイル。
Linqを使うのであればSystem.Data.SQLite.Linq.dllも必要。

ひとまずは、System.Data.SQlite.dllで遊んでみます。
今回遊ぶのは2010C#のコンソールアプリを使っています。

参照設定から先ほどのdllを追加します。
そして、using System.Data.SQLite;を追加します。

ここまで準備できれば、あとはコードを書いていくのみです。

なお、System.Data.SQLiteのDocumentは、下記からダウンロードできるようになっています。
こちらを手元に用意しておいたほうが、のちのち便利よいと思います
https://system.data.sqlite.org/index.html/doc/trunk/www/index.wiki

2016年1月11日月曜日

Nuget

.netのオープンソースパッケージ管理システムです。
perlだとcpanmコマンド、Rubyならgemコマンドをあたりを想像すればよいのかなと。

通常、Visual Studioに備わっているものですが、Expressだと使えないので
コマンドラインで使えるツールを別途ダウンロードして使うことになります。

NugetのサイトのダウンロードにいくとCommandlineツールがあります。
https://www.nuget.org/


現在は、version3.3.0が最新のようです。
ダウンロードします。

※参考
nugetは自分自身をアップデートする機能を持っていて以下コマンドを実行するとアップデートされるそうな。
nuget update -self

では、さっそく使ってみます。
Windows API Code Packでもダウンロードしてみます。
その前に、nugetのサイトで、Package名を調べてみる。


WindowsAPICodePack-Shell でいいみたい。

nuget install WindowsAPICodePack-Shell で実行した場所にダウンロードされます。

あとは、dll追加して使えばよい感じですね。

2016年1月2日土曜日

GUID取得方法

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            GuidAttribute hogeAttribute = (GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute));
            Console.WriteLine(hogeAttribute.Value);
        }
    }
}