トップ回答者
レコード存在チェックして更新

質問
回答
-
他には、DataTableを使う方法ではないので話が飛びますが、以下のようなものもあります。
ご参考までに・・・
SqlServerやOracleであれば、Margeがあります。
ただし、SqlServerは2008以降、Oracleは、たしか9i以降からサポートしています。
Marge文は、対象のレコードがもしあれば更新、なければ追加といったことが可能な構文を
一つのクエリで書くことができます。
つまり、レコード存在チェックのSELECT文、及びその結果に応じたINSERTやUPDATEの
一連の流れを一度に行うことができるものです。
SQLSERVER
http://msdn.microsoft.com/ja-jp/library/bb510625(v=SQL.100).aspx
http://www.atmarkit.co.jp/fdb/rensai/sqlsvr08rev/3/sqlsvr08rev03_02.html
ORACLE
http://www.shift-the-oracle.com/sql/merge.html
http://www.atmarkit.co.jp/fdb/rensai/orasql12/orasql12_1.html
- 回答としてマーク TAKAPI 2010年12月10日 6:53
-
SqlDataAdapter ではなくてベタな方法ですが、サンプルを書いてみました。
SQL Server 2005 以降用です。
テーブルは table1、主キーは field1、データは field2 を想定しています。
'Imports System.Data.SqlClient
Using connection As New SqlConnection()
'接続情報
Dim connectionString = New SqlConnectionStringBuilder()
connectionString.IntegratedSecurity = True
connectionString.DataSource = ".\SQLExpress"
connectionString.MultipleActiveResultSets = True
connection.ConnectionString = connectionString.ToString()
connection.Open()
Using transaction = connection.BeginTransaction()
Using commandR = connection.CreateCommand(), _
commandC = connection.CreateCommand(), _
commandU = connection.CreateCommand()
'データ取得用
commandR.Transaction = transaction
commandR.CommandText = _
"SELECT field2 FROM dbo.table1" & _
" WHERE field1 = @field1"
commandR.Parameters.Add("@field1", SqlDbType.Int)
'データ追加用
commandC.Transaction = transaction
commandC.CommandText = _
"INSERT INTO dbo.table1 (field1, field2)" & _
" VALUES (@field1, @field2)"
commandC.Parameters.Add("@field1", SqlDbType.Int)
commandC.Parameters.Add("@field2", SqlDbType.NVarChar)
'データ更新用
commandU.Transaction = transaction
commandU.CommandText = _
"UPDATE dbo.table1" & _
" SET field2 = @field2" & _
" WHERE field1 = @field1"
commandU.Parameters.Add("@field1", SqlDbType.Int)
commandU.Parameters.Add("@field2", SqlDbType.NVarChar)
'何かの値を元に・・・
For Each field1 In New Integer() {10, 20, 30}
'データを取得してみて、
commandR.Parameters("@field1").Value = field1
Using reader = commandR.ExecuteReader()
If Not reader.Read() Then
'取得できなかったら追加
commandC.Parameters("@field1").Value = field1
commandC.Parameters("@field2").Value = "新しい値"
commandC.ExecuteNonQuery()
Else
'取得できれば更新
commandU.Parameters("@field1").Value = field1
commandU.Parameters("@field2").Value = _
reader("field2").ToString() & "の更新値"
If commandU.ExecuteNonQuery() = 0 Then
Throw New Exception()
End If
End If
End Using
Next
End Using
'すべて正常に処理できた場合だけコミット
transaction.Commit()
End Using
End Using- 回答としてマーク TAKAPI 2010年12月10日 6:53
-
DataAdapter の例も一応挙げておきます。慣れるとさほど苦にはならないと思うんですが・・・
' 型推論を使ってます。レイトバインディングじゃないのであしからず。 ' あとコードは試してませんので注意。 Using connection = New SqlConnection("接続文字列") connection.Open() Dim transaction = connection.BeginTransaction() Try ' プライマリキーは必ず含める Dim command = New SqlCommand("SELECT id, name, address FROM person WHERE name = @name", connection) ' パラメータを指定して検索 command.Parameters.AddWithValue("@name", "山本太郎") ' テーブル取得 Dim adapter = New SqlDataAdapter(command) Dim builder = New SqlCommandBuilder(adapter) Dim dt As New DataTable() adapter.Fill(dt) ' DataTable 側にプライマリキーを指定しておく dt.PrimaryKey = New DataColumn() {dt.Columns("id")} ' 山本太郎が婿入りして鈴木太郎になった If (dt.Rows.Count = 0) Then ' データが存在しないので作成 Dim row = dt.NewRow() row("name") = "鈴木太郎" row("address") = "東京都" dt.Rows.Add(row) Else ' 存在したので更新 dt.Rows(0)("name") = "鈴木太郎" End If ' テーブル更新 adapter.Update(dt) transaction.Commit() Catch ex As Exception transaction.Rollback() Finally transaction.Dispose() End Try End Using
あとコーディングが面倒であれば、ADO.NET のラッパーとか作って管理する方法もあります。
http://d.hatena.ne.jp/hilapon/20100709/1278734481
ひらぽん http://d.hatena.ne.jp/hilapon/- 回答としてマーク TAKAPI 2010年12月10日 6:53
すべての返信
-
他には、DataTableを使う方法ではないので話が飛びますが、以下のようなものもあります。
ご参考までに・・・
SqlServerやOracleであれば、Margeがあります。
ただし、SqlServerは2008以降、Oracleは、たしか9i以降からサポートしています。
Marge文は、対象のレコードがもしあれば更新、なければ追加といったことが可能な構文を
一つのクエリで書くことができます。
つまり、レコード存在チェックのSELECT文、及びその結果に応じたINSERTやUPDATEの
一連の流れを一度に行うことができるものです。
SQLSERVER
http://msdn.microsoft.com/ja-jp/library/bb510625(v=SQL.100).aspx
http://www.atmarkit.co.jp/fdb/rensai/sqlsvr08rev/3/sqlsvr08rev03_02.html
ORACLE
http://www.shift-the-oracle.com/sql/merge.html
http://www.atmarkit.co.jp/fdb/rensai/orasql12/orasql12_1.html
- 回答としてマーク TAKAPI 2010年12月10日 6:53
-
> 他には、DataTableを使う方法ではないので話が飛びますが、以下のようなものもあります。
DataTable 使うなら、trapemiya さん仰るとおり Update が一番ですが、ちょうどいま MySQL 使ってて同じようなことをしてましたので、honefai さんとおなじく参考までに挙げておきます。
MySQL なら INSERT ... ON DUPLICATE KEY UPDATE 構文というのがあります。
http://dev.mysql.com/doc/refman/5.1/ja/insert-on-duplicate.html
こちらは INSERT 文に ON DUPLICATE KEY UPDATE を指定し、UNIQUE インデックスか PRIMARY KEY 内で重複するデータを挿入しようとしたら、UPDATE が実行されます。
#あくまで参考までに・・・
ひらぽん http://d.hatena.ne.jp/hilapon/ -
SqlDataAdapter ではなくてベタな方法ですが、サンプルを書いてみました。
SQL Server 2005 以降用です。
テーブルは table1、主キーは field1、データは field2 を想定しています。
'Imports System.Data.SqlClient
Using connection As New SqlConnection()
'接続情報
Dim connectionString = New SqlConnectionStringBuilder()
connectionString.IntegratedSecurity = True
connectionString.DataSource = ".\SQLExpress"
connectionString.MultipleActiveResultSets = True
connection.ConnectionString = connectionString.ToString()
connection.Open()
Using transaction = connection.BeginTransaction()
Using commandR = connection.CreateCommand(), _
commandC = connection.CreateCommand(), _
commandU = connection.CreateCommand()
'データ取得用
commandR.Transaction = transaction
commandR.CommandText = _
"SELECT field2 FROM dbo.table1" & _
" WHERE field1 = @field1"
commandR.Parameters.Add("@field1", SqlDbType.Int)
'データ追加用
commandC.Transaction = transaction
commandC.CommandText = _
"INSERT INTO dbo.table1 (field1, field2)" & _
" VALUES (@field1, @field2)"
commandC.Parameters.Add("@field1", SqlDbType.Int)
commandC.Parameters.Add("@field2", SqlDbType.NVarChar)
'データ更新用
commandU.Transaction = transaction
commandU.CommandText = _
"UPDATE dbo.table1" & _
" SET field2 = @field2" & _
" WHERE field1 = @field1"
commandU.Parameters.Add("@field1", SqlDbType.Int)
commandU.Parameters.Add("@field2", SqlDbType.NVarChar)
'何かの値を元に・・・
For Each field1 In New Integer() {10, 20, 30}
'データを取得してみて、
commandR.Parameters("@field1").Value = field1
Using reader = commandR.ExecuteReader()
If Not reader.Read() Then
'取得できなかったら追加
commandC.Parameters("@field1").Value = field1
commandC.Parameters("@field2").Value = "新しい値"
commandC.ExecuteNonQuery()
Else
'取得できれば更新
commandU.Parameters("@field1").Value = field1
commandU.Parameters("@field2").Value = _
reader("field2").ToString() & "の更新値"
If commandU.ExecuteNonQuery() = 0 Then
Throw New Exception()
End If
End If
End Using
Next
End Using
'すべて正常に処理できた場合だけコミット
transaction.Commit()
End Using
End Using- 回答としてマーク TAKAPI 2010年12月10日 6:53
-
DataAdapter の例も一応挙げておきます。慣れるとさほど苦にはならないと思うんですが・・・
' 型推論を使ってます。レイトバインディングじゃないのであしからず。 ' あとコードは試してませんので注意。 Using connection = New SqlConnection("接続文字列") connection.Open() Dim transaction = connection.BeginTransaction() Try ' プライマリキーは必ず含める Dim command = New SqlCommand("SELECT id, name, address FROM person WHERE name = @name", connection) ' パラメータを指定して検索 command.Parameters.AddWithValue("@name", "山本太郎") ' テーブル取得 Dim adapter = New SqlDataAdapter(command) Dim builder = New SqlCommandBuilder(adapter) Dim dt As New DataTable() adapter.Fill(dt) ' DataTable 側にプライマリキーを指定しておく dt.PrimaryKey = New DataColumn() {dt.Columns("id")} ' 山本太郎が婿入りして鈴木太郎になった If (dt.Rows.Count = 0) Then ' データが存在しないので作成 Dim row = dt.NewRow() row("name") = "鈴木太郎" row("address") = "東京都" dt.Rows.Add(row) Else ' 存在したので更新 dt.Rows(0)("name") = "鈴木太郎" End If ' テーブル更新 adapter.Update(dt) transaction.Commit() Catch ex As Exception transaction.Rollback() Finally transaction.Dispose() End Try End Using
あとコーディングが面倒であれば、ADO.NET のラッパーとか作って管理する方法もあります。
http://d.hatena.ne.jp/hilapon/20100709/1278734481
ひらぽん http://d.hatena.ne.jp/hilapon/- 回答としてマーク TAKAPI 2010年12月10日 6:53