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', 'こなつ', '♀', '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