C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: テーブルインデックスのUNIQUE情報取得


(過去ログ 107 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■63604 / inTopicNo.1)  テーブルインデックスのUNIQUE情報取得
  
□投稿者/ asuka (8回)-(2012/09/11(Tue) 13:13:30)

分類:[C#] 

いつもお世話になっております。

データベース(Sql, mdb)のテーブルインデックスが一意(UNIQUE)かどうかの判断を行いたいと考えております。

いくつかのサイトには下記のようにしてあたかも取得出来るかのように記載されています。

string[] restrictionValues = new string[] { null, null, "TableName", null };
DataTable tbl = con.GetSchema("Indexes", restrictionValues);
foreach (DataRow row in tbl.Rows)
{
 string str = string.Format("{0,10}\t{1,15}\t{2,7}\t{3,20}\t{4,5}",
 row["TABLE_NAME"], row["INDEX_NAME"], row["UNIQUE"], row["COLUMN_NAME"]);
}

これを行うとUNIQUEを指定した段階で例外が発生します。
その他の値は取れます。

GetSchemaからUNIQUE情報を取得することは無理なのでしょうか?

他の方法でも取得方法があれば教えて頂けると幸いです。

引用返信 編集キー/
■63605 / inTopicNo.2)  Re[1]: テーブルインデックスのUNIQUE情報取得
□投稿者/ shu (71回)-(2012/09/11(Tue) 17:28:16)
No63604 (asuka さん) に返信

> string[] restrictionValues = new string[] { null, null, "TableName", null };
数が足りないしテーブル名はIndex=4に指定しないと駄目なはず。


> DataTable tbl = con.GetSchema("Indexes", restrictionValues);
> foreach (DataRow row in tbl.Rows)
> {
>  string str = string.Format("{0,10}\t{1,15}\t{2,7}\t{3,20}\t{4,5}",
>  row["TABLE_NAME"], row["INDEX_NAME"], row["UNIQUE"], row["COLUMN_NAME"]);
Formatのインデックスと引数の数があっていませんが大丈夫でしょうか?


> }
>
> これを行うとUNIQUEを指定した段階で例外が発生します。
> その他の値は取れます。
TableNameという名のインデックスが存在しているのでしょうか?
例外はなんでしょう?


引用返信 編集キー/
■63606 / inTopicNo.3)  Re[2]: テーブルインデックスのUNIQUE情報取得
□投稿者/ asuka (9回)-(2012/09/12(Wed) 13:44:37)
2012/09/12(Wed) 14:15:26 編集(投稿者)
2012/09/12(Wed) 13:45:00 編集(投稿者)

No63605 (shu さん) に返信
レスありがとうございます。

>>string[] restrictionValues = new string[] { null, null, "TableName", null };
> 数が足りないしテーブル名はIndex=4に指定しないと駄目なはず。
今までもGetSchema自体はよく使っていまして、実際これでループで回していますが、
3番目に指定したテーブルのインデックス名は取得出来てはいます。
※row["TABLE_NAME"]は指定しているので変わらずインデックスの個数分ループします。


>>DataTable tbl = con.GetSchema("Indexes", restrictionValues);
>>foreach (DataRow row in tbl.Rows)
>>{
>> string str = string.Format("{0,10}\t{1,15}\t{2,7}\t{3,20}\t{4,5}",
>> row["TABLE_NAME"], row["INDEX_NAME"], row["UNIQUE"], row["COLUMN_NAME"]);
> Formatのインデックスと引数の数があっていませんが大丈夫でしょうか?

こちらは掲載ミスでした、間際らしくてすみません。
特に問題ないです。


>>これを行うとUNIQUEを指定した段階で例外が発生します。
>>その他の値は取れます。
> TableNameという名のインデックスが存在しているのでしょうか?
> 例外はなんでしょう?

TableNameという名前のテーブルの、GetSchemaの第一引数で指定したもの(Indexes)の、
スキームを取得する、といった意図になるかと思っています。
問題は、インデックスのスキームを取得しているのに「一意」かどうかの情報の取り方が分からない、といったところです。
今思うに、GetSchemaではクラスタ化かどうかまでは分かりますが、「一意」情報は分からないという決断に達しました。
※クラスタ化の場合row["CLUSTERD"]で文字列が取得出来ます。

このように考えたのは、rowのItemArrayの各配列は予約された文字列から取得することが出来ますが、
実際添え字の中身を直接デバッグで見てみるとboolの値がなく、一意かどうかの情報もなさそうだからです。
ItemArray {object[8]} object[]
[0] "DBNAME" object {string}
[1] "dbo" object {string}
[2] "INDEXNAME" object {string}
[3] "DGNAME" object {string}
[4] "dbo" object {string}
[5] "TableName" object {string}
[6] "INDEXNAME" object {string}
[7] "NONCLUSTERED" object {string}
※内容は変更しています。

例外は以下のように出ます。
「 列 'UNIQUE' はテーブル Indexes に属していません。」

引用返信 編集キー/
■63607 / inTopicNo.4)  Re[3]: テーブルインデックスのUNIQUE情報取得
□投稿者/ 魔界の仮面弁士 (57回)-(2012/09/12(Wed) 14:47:03)
No63606 (asuka さん) に返信
> 今までもGetSchema自体はよく使っていまして、実際これでループで回していますが、
では、ループで回した場合はどうなりますか?

確認のため、System.Windows.Forms.DataGridView あたりに
 dataGridView1.DataSource = con.GetSchema("Indexes");
を実行して、全定義を表示してみることをお奨めします。

接続先(SqlClient、OleDb+ACE、OleDb+Jet 等)によって、もしかしたら
列定義が微妙に異なるのかもしれません(未調査につき眉唾で)。


なお、OleDbConnection.GetSchema メソッドに相当する機能としては、
 ・OleDbConnection.GetOleDbSchemaTable メソッド
 ・ADODB.Recordset.OpenSchema メソッド
が存在します。


SQL Server の場合は、SYS.INDEXES カタログビューから取得するか、
sp_MShelpindex / sp_MShelpcolumns ストアドプロシージャーで。
引用返信 編集キー/
■63608 / inTopicNo.5)  Re[3]: テーブルインデックスのUNIQUE情報取得
□投稿者/ shu (72回)-(2012/09/12(Wed) 14:53:23)
No63606 (asuka さん) に返信

> このように考えたのは、rowのItemArrayの各配列は予約された文字列から取得することが出来ますが、
> 実際添え字の中身を直接デバッグで見てみるとboolの値がなく、一意かどうかの情報もなさそうだからです。
> ItemArray {object[8]} object[]
> [0] "DBNAME" object {string}
> [1] "dbo" object {string}
> [2] "INDEXNAME" object {string}
> [3] "DGNAME" object {string}
> [4] "dbo" object {string}
> [5] "TableName" object {string}
> [6] "INDEXNAME" object {string}
> [7] "NONCLUSTERED" object {string}
> ※内容は変更しています。
なぜmdbなのにdboとか出てくるのでしょう?
OleDBConnectionによるMDB接続の話ではないのですか?


> 例外は以下のように出ます。
> 「 列 'UNIQUE' はテーブル Indexes に属していません。」
SqlServerならスキーマテーブルはこれ。
http://msdn.microsoft.com/ja-jp/library/vstudio/ms254969

DataReader.GetSchemaTableを使うサンプルが載っているサイト。
下の方がSchemaとKey情報だけに絞っているので効率が良さそう。
http://www.java2s.com/Tutorial/CSharp/0560__ADO.Net/GettableschemafromSqlDataReader.htm
http://stackoverflow.com/questions/5849701/how-to-get-columns-primary-key-constraints-using-sqlconnection-getschema

引用返信 編集キー/
■63609 / inTopicNo.6)  Re[4]: テーブルインデックスのUNIQUE情報取得
□投稿者/ asuka (10回)-(2012/09/12(Wed) 16:37:34)
No63607 (魔界の仮面弁士 さん) に返信
レスありがとうございます。

> 確認のため、System.Windows.Forms.DataGridView あたりに
>  dataGridView1.DataSource = con.GetSchema("Indexes");
> を実行して、全定義を表示してみることをお奨めします。
時間を見つけて確認したいと思います。
Silverlightのサーバ側の処理なのでUIにバインド出来ないので目視しようかと思います。

> 接続先(SqlClient、OleDb+ACE、OleDb+Jet 等)によって、もしかしたら
> 列定義が微妙に異なるのかもしれません(未調査につき眉唾で)。
>
>
> なお、OleDbConnection.GetSchema メソッドに相当する機能としては、
>  ・OleDbConnection.GetOleDbSchemaTable メソッド
>  ・ADODB.Recordset.OpenSchema メソッド
> が存在します。
実際のコーディングですが、SqlClientとOleDbConnectionをラッパしたものを使っています。
(Microsoft.Practices.EnterpriseLibrary.Data.Database / DbConnection)
SqlならSqlConnectionを、MdbならOleDbConnectionを使ってくれるクラスです。
2年以上使っていますが双方のクラスと同じ動作をしてくれます。

GetOleDbSchemaTableに関しては調査済で、カラム固有の情報でインデックスの情報は扱っていませんでした。
この列定義にあるIsUniqueはインデックスの「一意」かどうかではなく、列に関しての情報でした。
※確か列がIDかどうかだったと記憶しています。

ADODB.Recordsetの方もデータに関わるもので、実際はADODB.ConnectionとADOX.Indexを組み合わせることでUNIQUE情報を取得出来ました。

現状はこれで妥協しようかと思っています。


> SQL Server の場合は、SYS.INDEXES カタログビューから取得するか、
> sp_MShelpindex / sp_MShelpcolumns ストアドプロシージャーで。
SQLの場合はsp_helpindexでも取れることが分かっていたのですが、mdb対応のためspの使用は止めていました。

ご意見ありがとうございます。

引用返信 編集キー/
■63610 / inTopicNo.7)  Re[5]: テーブルインデックスのUNIQUE情報取得
□投稿者/ asuka (11回)-(2012/09/12(Wed) 16:44:15)
shu様。

レスありがとうございます。

>なぜmdbなのにdboとか出てくるのでしょう?
>OleDBConnectionによるMDB接続の話ではないのですか?
冒頭でデータベース(Sql, mdb)と書いたのですが、伝わりにくかったかと思います。
今回はSql、Mdb双方に対して対応します。
先ほど記載したのはSqlの場合の結果でした。
分かりづらくてすみません。

1つめのURLで定義があるのですが、これを見ても「一意」かどうかは取れそうにないといことが分かりました。
※期待していたのは、8配列のItemArrayを持ってるのでここで表記されていない2つのうちどちらかに「一意」情報がないか?ということでしたがないようでした。

GetSchemaTableに関しては魔界の仮面弁士さんのお返事にも書かせて頂きました通り、列に関する情報で、テーブルが持つインデックスの情報ではありませんでした。

引用返信 編集キー/
■63613 / inTopicNo.8)  Re[6]: テーブルインデックスのUNIQUE情報取得
□投稿者/ asuka (12回)-(2012/09/13(Thu) 16:30:37)
2012/09/14(Fri) 09:19:13 編集(投稿者)

わたしなりのまとめです。
色々とアドバイスありがとうございました。

■結論
・GetSchemaからは判断不可。
→テーブルのインデックスがユニークがどうかの情報をもっていない。
・GetSchemaTableからは判断不可。
→列に対する情報なのでIsUniqueは列がユニークかどうかでインデックスについてではない。
SqlConnection、OleDbConnectionからでは判断出来ない。

■考察
・Microsoft ActiveX Data Objects 2.5 Libraryを用いた取得なら可能
サンプル - 指定したindexが一意だったら削除して一意を外して再作成

ADODB.Connection adocon = new ADODB.Connection();
ADOX.Index addIndex = new ADOX.Index();
ADOX.Catalog adocatalog = new Catalog();
bool isUniqueIndex = false;
List<string> indexColumnlist = new List<string>();

string constr = "Provider=SQLOLEDB;";
constr += string.Format("Data Source={0};","ServerName");
constr += string.Format("Initial Catalog={0};","DbName");
constr += "Integrated Security = SSPI;";

adocon.Open(constr);
adocatalog.ActiveConnection = adocon;

// 指定したindex検索
foreach (ADOX.Index index in adocatalog.Tables[tablename].Indexes)
{
 if (index.Name.ToUpper() == "Hogehoge_index".ToUpper())
 {
  if (index.Unique)
  {
   isUniqueIndex = true;
   foreach (ADOX.Column colume in index.Columns)
   {
    indexColumnlist.Add(colume.Name);
   }
   break;
  }
 }
}

// 再作成
if (isUniqueIndex)
{
 adocatalog.Tables[tablename].Indexes.Delete("Hogehoge_index");
 addIndex.Name = "Hogeho_index";
 addIndex.Unique = false;
 for (int k = 0; k < indexColumnlist.Count; k++)
 {
  addIndex.Columns.Append(indexColumnlist[k]);
 }
 adocatalog.Tables[tablename].Indexes.Append(addIndex);
}

adocon.Close();
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -