tag:crieit.net,2005:https://crieit.net/tags/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9/feed 「データベース」の記事 - Crieit Crieitでタグ「データベース」に投稿された最近の記事 2020-03-09T00:34:26+09:00 https://crieit.net/tags/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9/feed tag:crieit.net,2005:PublicArticle/15752 2020-03-09T00:34:26+09:00 2020-03-09T00:34:26+09:00 https://crieit.net/posts/mysql-postgresql-null MySQLやPostgreSQLにおけるNULLは、不明な値であり計算に使うと結果がNULLになってしまうことがある <p>私はプログラミング言語におけるNULLは、「何もない値」または「何も示していない値」という定義で理解しています。<br /> ところがSQLにおけるNULLでは、この単純な理解が通用しないことを知りました。</p> <p>先に結論を言ってしまうと、<strong>「NULLとは不明な値のことである」</strong>という解釈で落ち着いたのですが。<br /> これの何が問題なのか、解説します。</p> <h2 id="MySQLにおけるNULLとは、「存在しない不明な値」のことである"><a href="#MySQL%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8BNULL%E3%81%A8%E3%81%AF%E3%80%81%E3%80%8C%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84%E4%B8%8D%E6%98%8E%E3%81%AA%E5%80%A4%E3%80%8D%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%82%E3%82%8B">MySQLにおけるNULLとは、「存在しない不明な値」のことである</a></h2> <p>MySQLのリファレンスを読むと、NULLとは不明な値であることがわかります。</p> <blockquote> <p>NULL値に慣れるまでは驚くかもしれません。<br /> 概念的には、NULLは<strong>「存在しない不明な値」</strong>を意味し、ほかの値とは多少異なる方法で扱われます。<br /> <a target="_blank" rel="nofollow noopener" href="https://dev.mysql.com/doc/refman/5.6/ja/working-with-null.html">https://dev.mysql.com/doc/refman/5.6/ja/working-with-null.html</a> より</p> </blockquote> <p>不明な値を直訳で解釈すると、<strong>「何が入っているのか分からない値」</strong>という意味になります。</p> <h2 id="NULLを算術(計算)で使うとNULLになる"><a href="#NULL%E3%82%92%E7%AE%97%E8%A1%93%EF%BC%88%E8%A8%88%E7%AE%97%EF%BC%89%E3%81%A7%E4%BD%BF%E3%81%86%E3%81%A8NULL%E3%81%AB%E3%81%AA%E3%82%8B">NULLを算術(計算)で使うとNULLになる</a></h2> <p>一般的なプログラミング言語では、NULLを使った計算では警告や例外が発生するか、もしくは「0」という値に自動変換されて計算されます。</p> <pre><code class="php"><?php $a = 10 - null; echo $a; // 10 </code></pre> <p>ところがMySQLでは「10」にもならないし、エラーにもなりません。</p> <pre><code class="sql">mysql> SELECT 10 - NULL; +-----------+ | 10 - NULL | +-----------+ | NULL | +-----------+ 1 row in set (0.00 sec) </code></pre> <p>この挙動はPostgreSQLでも同様で、「10 - NULL」はNULLになります。</p> <pre><code class="sql">postgres=# \pset null '(null)' Null display is "(null)". postgres=# SELECT 10 - NULL; ?column? ---------- (null) (1 row) </code></pre> <h3 id="NULLは算術比較できない"><a href="#NULL%E3%81%AF%E7%AE%97%E8%A1%93%E6%AF%94%E8%BC%83%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">NULLは算術比較できない</a></h3> <p>MySQLのリファレンスを読み進めていくと、<strong>算術比較はできません</strong>と書いてあります。</p> <blockquote> <p>=、<br /> <a target="_blank" rel="nofollow noopener" href="https://dev.mysql.com/doc/refman/5.6/ja/working-with-null.html">https://dev.mysql.com/doc/refman/5.6/ja/working-with-null.html</a> より</p> </blockquote> <p>つまりNULLは不明な値なので、算術比較の結果もまた、不明になってしまうのだろうと私は解釈しました。</p> <h2 id="NULLとなりえる値を、計算で使うのはやめよう"><a href="#NULL%E3%81%A8%E3%81%AA%E3%82%8A%E3%81%88%E3%82%8B%E5%80%A4%E3%82%92%E3%80%81%E8%A8%88%E7%AE%97%E3%81%A7%E4%BD%BF%E3%81%86%E3%81%AE%E3%81%AF%E3%82%84%E3%82%81%E3%82%88%E3%81%86">NULLとなりえる値を、計算で使うのはやめよう</a></h2> <p>MySQLやPostgreSQLにおけるNULLの挙動を総括すると、たとえテーブル定義の型が整数型(INT型)であったとしても、<strong>「NOT NULL」制約のないカラムをSQLでそのまま計算に使わないほうが良い</strong>と言えます。</p> <p>ただ計算に使えない数値というのも困りますので、対処法を考えてみます。<br /> 私が思いつく限り、対処法は大きく分けて2つあります。</p> <h3 id="テーブル定義(DDL)にNOT NULLを追加する"><a href="#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E5%AE%9A%E7%BE%A9%EF%BC%88DDL%EF%BC%89%E3%81%ABNOT+NULL%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B">テーブル定義(DDL)にNOT NULLを追加する</a></h3> <p>SQL上で計算に使う値であれば、テーブル定義を「NOT NULL DEFAULT 0」にして、必ず数値がある状態にします。</p> <p>値が「0」であれば算術に使うことができるため、想定外の計算トラブルは抑制できます。</p> <h3 id="IFNULL()などのSQL関数を使って、NULL値を回避する"><a href="#IFNULL%28%29%E3%81%AA%E3%81%A9%E3%81%AESQL%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81NULL%E5%80%A4%E3%82%92%E5%9B%9E%E9%81%BF%E3%81%99%E3%82%8B">IFNULL()などのSQL関数を使って、NULL値を回避する</a></h3> <p>MySQLにはIFNULL()という、SQL関数があります。<br /> IFNULLとは、「もしNULLであれば」を判定する関数です。</p> <p>これを使って、NULLであれば「0」に変換して計算します。</p> <pre><code class="sql">mysql> SELECT 10 - IFNULL(NULL, 0); +----------------------+ | 10 - IFNULL(NULL, 0) | +----------------------+ | 10 | +----------------------+ </code></pre> <p>テーブル定義で「NOT NULL」制約を使えないのであれば、NULL判定をしてデフォルト値を与えましょう。<br /> NULLを回避することによって、計算結果がNULLになってしまう問題を防げます。</p> <h2 id="さいごに"><a href="#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB">さいごに</a></h2> <p>MySQLやPostgreSQLにおけるNULLとは、特異な値であることを学びました。<br /> だからMySQLのリファレンスにも、<strong>「NULL値に慣れるまでは驚くかもしれません。」</strong>と、あえて書いてあるのだと推測します。</p> <p>なおデータベースにおけるNULLの扱い多くのRDBMSで共通ですが、Oracleだけは特別みたいです。</p> <blockquote> <p>以上の NULL に関する事柄のほとんどは、PostgreSQL に限らず、多くの RDBMS で共通ですが、重要な例外が1つあります。<br /> <strong>Oracleでは、NULL を含む文字列結合において NULL を返しません。</strong><br /> つまり select 'abc' || null from dual; の結果は abc になります。<br /> <a target="_blank" rel="nofollow noopener" href="https://oss-db.jp/dojo/dojo_08">https://oss-db.jp/dojo/dojo_08</a> より</p> </blockquote> <p>本記事ではデータベースにおけるNULLを取り上げましたが、NULL値の挙動や扱い方は、プログラミング言語によっても変わります。<br /> プログラム内でNULLを使うときは、<strong>「各プログラミング言語の参考書やリファレンスで、NULLの挙動を確認しておくのが良さそう」</strong>です。</p> このすみ tag:crieit.net,2005:PublicArticle/15376 2019-09-04T09:46:55+09:00 2019-09-04T09:46:55+09:00 https://crieit.net/posts/C-Access 【C#】Accessデータベースでデータを追加・更新・削除してみる <p>先日、データの取得までやったので<br /> さくっと追加・更新・削除もついでにやってみました。<br /> (だいぶ簡単にですが)</p> <p>プログラムは前回のものを流用しています。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2018/09/08/post-5965/" target="_blank" rel="noopener" data-blogcard="1">【C#】Microsoft Access Driver でAccessデータベースからデータを取得</a></p> <h2 id="画面の修正"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BF%AE%E6%AD%A3">画面の修正</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess2_000.jpg" alt="画面の修正" /></p> <p>画面に追加・更新・削除ボタンを新設します。</p> <h2 id="プログラム"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0">プログラム</a></h2> <p>Form1.cs</p> <pre><code>using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Data.Odbc; namespace SampleAccessDatabase { public partial class Form1 : Form { /// <summary> /// 接続文字列 /// </summary> private static string CONNECTION_STRING = @"Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=D:\Sample.accdb; Uid=; Pwd =; "; /// <summary> /// 起動時の処理. /// </summary> public Form1() { InitializeComponent(); // DataGridViewの設定 dataGridView1.AutoGenerateColumns = false; dataGridView1.Columns.Add("No", "No"); dataGridView1.Columns.Add("Name", "名前"); dataGridView1.Columns.Add("Sex", "性別"); dataGridView1.Columns.Add("Age", "年齢"); dataGridView1.Columns.Add("KbnCd", "種別"); dataGridView1.Columns.Add("Favorite", "好物"); dataGridView1.Columns[0].DataPropertyName = "No"; dataGridView1.Columns[1].DataPropertyName = "Name"; dataGridView1.Columns[2].DataPropertyName = "Sex"; dataGridView1.Columns[3].DataPropertyName = "Age"; dataGridView1.Columns[4].DataPropertyName = "KbnCd"; dataGridView1.Columns[5].DataPropertyName = "Favorite"; dataGridView1.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic; // データ検索 search(); } /// <summary> /// データを検索、表示します. /// </summary> private void search() { // データ取得 DataTable dt = new DataTable(); using (OdbcConnection con = new OdbcConnection(CONNECTION_STRING)) { con.Open(); string sql = "SELECT * FROM TBLCAT"; using (OdbcCommand cmd = new OdbcCommand(sql, con)) { using (OdbcDataAdapter adapter = new OdbcDataAdapter(cmd)) { adapter.Fill(dt); } } } dataGridView1.DataSource = dt; dataGridView1.Sort(dataGridView1.Columns[0], ListSortDirection.Ascending); } /// <summary> /// 追加ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_add_Click(object sender, EventArgs e) { using (OdbcConnection con = new OdbcConnection(CONNECTION_STRING)) { con.Open(); string sql = "INSERT INTO TBLCAT VALUES(10, '5', 'こなつ', '&#x2640;', '6', '03', '布団')"; using (OdbcCommand cmd = new OdbcCommand(sql, con)) { int ret = cmd.ExecuteNonQuery(); if (ret != 1) { MessageBox.Show("登録に失敗しました。"); } } } // 再検索 search(); } /// <summary> /// 更新ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_upd_Click(object sender, EventArgs e) { using (OdbcConnection con = new OdbcConnection(CONNECTION_STRING)) { con.Open(); string sql = "UPDATE TBLCAT SET FAVORITE = 'CIAOちゅ0る' WHERE NAME = 'りく'"; using (OdbcCommand cmd = new OdbcCommand(sql, con)) { int ret = cmd.ExecuteNonQuery(); if (ret != 1) { MessageBox.Show("更新に失敗しました。"); } } } // 再検索 search(); } /// <summary> /// 削除ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_del_Click(object sender, EventArgs e) { using (OdbcConnection con = new OdbcConnection(CONNECTION_STRING)) { con.Open(); string sql = "DELETE FROM TBLCAT WHERE NAME = 'こなつ'"; using (OdbcCommand cmd = new OdbcCommand(sql, con)) { int ret = cmd.ExecuteNonQuery(); if (ret != 1) { MessageBox.Show("削除に失敗しました。"); } } } // 再検索 search(); } } } </code></pre> <p>データ操作後、再検索できるように検索メソッドに処理を分離し、<br /> 新設したボタンそれぞれのクリックイベントにてデータ操作を実行します。</p> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess2_001.jpg" alt="初期表示" /></p> <p>追加ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess2_002.jpg" alt="レコード追加" /></p> <p>こなつが追加されました。</p> <p>続いて更新ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess2_003.jpg" alt="データ更新" /></p> <p>りくの好物が更新されました。</p> <p>続いて削除ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess2_004.jpg" alt="データ削除" /></p> <p>こなつが削除されました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>Access編はこのあたりで終了しそうです。<br /> 次回はまだ特に決めていませんが、また何か新しいことを試してみたいですね。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15372 2019-09-03T09:55:41+09:00 2019-09-03T09:55:41+09:00 https://crieit.net/posts/C-Microsoft-Access-Driver-Access 【C#】Microsoft Access Driver でAccessデータベースからデータを取得 <p>昨日に引き続き?C#の話し。</p> <p>未だに、Accessを使ったツールやシステムがあって、個人的にはもうやめようよと思いながら、データを取得するサンプルをやってみました。<br /> (今では他にも素晴らしいDBがありますからね。)</p> <h2 id="ダウンロード"><a href="#%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89">ダウンロード</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://www.microsoft.com/ja-jp/download/details.aspx?id=13255" target="_blank" rel="noopener">ダウンロードサイト</a></p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_000.jpg" alt="ダウンロードサイト" /></p> <p>ダウンロードボタンをクリックします。</p> <h2 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h2> <p>ダウンロードした「AccessDatabaseEngine.exe」または「AccessDatabaseEngine_X64.exe」を実行します。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_001.jpg" alt="インストールウィザード" /></p> <p>インストールウィザード画面が表示されるので「次へ」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_002.jpg" alt="使用許諾契約同意画面" /></p> <p>使用許諾契約同意画面が表示されるので、「同意します」にチェックをして「次へ」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_003.jpg" alt="インストール先指定画面" /></p> <p>インストール先指定画面が表示されるので、特に指定がなければそのまま「インストール」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_004.jpg" alt="インストール画面" /></p> <p>インストール中。しばしお待ちを。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_005.jpg" alt="完了画面" /></p> <p>完了画面が表示されるので「OK」ボタンをクリックします。</p> <h2 id="プロジェクトの作成"><a href="#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90">プロジェクトの作成</a></h2> <p>VisualStudio2017で新しく WindowsForm プロジェクトを作成します。<br /> 今回は「SampleAccessDatabase」としました。</p> <h2 id="データベースの作成"><a href="#%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">データベースの作成</a></h2> <p>いつもサンプルで使っている、猫のデータをサンプルで使用します。<br /> Access Database は、Windows画面上で右クリック>「新規作成」>「Microsoft Access Database」より、手動で作成してください。</p> <h3 id="テーブル"><a href="#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB">テーブル</a></h3> <p>列の定義は次の通り。</p> <p>MSTKIND</p> <pre><code>区分コード 区分名 </code></pre> <p>TBLCAT</p> <pre><code>番号 名前 性別 年齢 種別 好物 </code></pre> <h3 id="データ"><a href="#%E3%83%87%E3%83%BC%E3%82%BF">データ</a></h3> <p>MSTKIND</p> <p>区分コード<br /> 区分名</p> <p>01<br /> キジトラ</p> <p>02<br /> 長毛種(不明</p> <p>03<br /> ミケ(っぽい</p> <p>04<br /> サビ</p> <p>09<br /> その他</p> <p>TBLCAT</p> <p>No<br /> 名前<br /> 性別<br /> 年齢<br /> 区分コード<br /> 好物</p> <p>1<br /> そら<br /> ♂<br /> 6<br /> 01<br /> 犬の人形</p> <p>2<br /> りく<br /> ♂<br /> 5<br /> 02<br /> 人間</p> <p>3<br /> うみ<br /> ♀<br /> 4<br /> 03<br /> 高級ウェットフード</p> <p>4<br /> こうめ<br /> ♀<br /> 2<br /> 04<br /> 横取りフード</p> <h2 id="画面の作成"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BD%9C%E6%88%90">画面の作成</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_006.jpg" alt="画面" /></p> <p>フォームにデータグリッドビューのみを配置したシンプルな画面を作成します。</p> <h2 id="プログラム"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0">プログラム</a></h2> <p>起動時にデータを取得して表示するようにします。</p> <p>Form1.cs</p> <pre><code>using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Data.Odbc; namespace SampleAccessDatabase { public partial class Form1 : Form { public Form1() { InitializeComponent(); // DataGridViewの設定 dataGridView1.AutoGenerateColumns = false; dataGridView1.Columns.Add("No", "No"); dataGridView1.Columns.Add("Name", "名前"); dataGridView1.Columns.Add("Sex", "性別"); dataGridView1.Columns.Add("Age", "年齢"); dataGridView1.Columns.Add("KbnCd", "種別"); dataGridView1.Columns.Add("Favorite", "好物"); dataGridView1.Columns[0].DataPropertyName = "No"; dataGridView1.Columns[1].DataPropertyName = "Name"; dataGridView1.Columns[2].DataPropertyName = "Sex"; dataGridView1.Columns[3].DataPropertyName = "Age"; dataGridView1.Columns[4].DataPropertyName = "KbnCd"; dataGridView1.Columns[5].DataPropertyName = "Favorite"; dataGridView1.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic; // データ取得 DataTable dt = new DataTable(); string connectionString = @"Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=D:\Sample.accdb; Uid=; Pwd =; "; using (OdbcConnection con = new OdbcConnection(connectionString)) { con.Open(); string sql = "SELECT * FROM TBLCAT"; using (OdbcCommand cmd = new OdbcCommand(sql, con)) { using (OdbcDataAdapter adapter = new OdbcDataAdapter(cmd)) { adapter.Fill(dt); } } } dataGridView1.DataSource = dt; } } } </code></pre> <p> </p> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/09/CSharpAccess1_007.jpg" alt="初期表示" /></p> <p>無事にデータが表示されました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>データベースへの接続をいくつか記事に書いてきましたが、<br /> Accessはバージョンや32bit、64bitと気を付けなければならないことが多く、<br /> ちょっと面倒な感じです。</p> <p>とはいえ、(ひと)昔前のシステムや、簡単なツールなんかでよく利用されているため<br /> それなりに需要はあるんだろうなとは思いつつ、何かのお役に立てれば。</p> <p>ではでは。</p> doraxdora