Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 5 - Last Post: Sep 8, 2015 11:03 PM Last Post By: Nakano Shintaro
Nakano Shintaro

Posts: 22
Registered: 8/25/04
ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 28, 2015 12:18 AM
こんにちは、中野と申します。
いつもお世話になっています。

<使用環境>
C++Builder XE5(Update2)
OS:Windows7 64ビット
InterBase:購入した製品にインストールされていたInterBaseを使用

DBXコンポーネント群を使用
SQLConnection
SQLDataSet
DataSetProvider
ClientDataSet
DataSource
DBGrid

データベース系のプログラムを作りながら、データベースの取り扱いを勉強しています。

DBGridに表示されたテーブルにレコードを挿入したいと考えています。
ClientDataSet->Insert();
これで、DBGridの画面上ではレコードは挿入されていますが、実際、セルにデータを入力してからデータベースに登録
すると、DBGrid画面上の表示とは違う所に追加しています。

例えば、2行目と3行目の間にレコードを挿入したい場合は、DBGridのカーソルを3行目に合わせて
ClientDataSet->Insert();
を実行すると、DBGridの画面上では2行目と3行目の間に新しいレコードが表示されています。
データベースにテーブルの変更および修正を登録すると、ランダムに新しく挿入したレコードが
登録されている。

インターネットで調べると、ClientDataSet->Insert();を実行する前に、カーソルがあるレコード番号を
保管し、挿入後に保管したレコード番号を再び元に戻す作業が必要と記載もありました。

個人的な考えですが、Insert()を実行するときは、レコードを挿入する場所を指定する必要があるのかと
思っていますが、皆目見当がつきません。

<データベースにテーブル内編集を登録する時>
SQLDataSet->CommandType = ctTable;
SQLDataSet->DbxCommandType = "Dbx.Table";
SQLDataSet->CommandText = TableName; // TableNameは、DBGridで選択しているテーブル名が入ります
ClientDataSet->Edit();
ClientDataSet->Post();
ClientDataSet->ApplyUpdates(-1);
SQLDataSet->CommandType = ctQuery;
SQLDataSet->DbxCommandType = "Dbx.SQL";
SQLDataSet->CommandText = "";

データベースに関して理解していない部分が多いのですが、
DBGrid画面上の表示通りにデータベースに登録する方法ありましたら、ご助言頂けると助かります。
参考になるインターネットサイトや書籍等ございましたら教えて貰えると助かります。

お忙しいところ、よろしくお願いします。
Nakano Shintaro

Posts: 22
Registered: 8/25/04
Re: ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 31, 2015 12:05 AM   in response to: Nakano Shintaro in response to: Nakano Shintaro
Nakano Shintaro wrote:
こんにちは、中野と申します。
いつもお世話になっています。

<使用環境>
C++Builder XE5(Update2)
OS:Windows7 64ビット
InterBase:購入した製品にインストールされていたInterBaseを使用

DBXコンポーネント群を使用
SQLConnection
SQLDataSet
DataSetProvider
ClientDataSet
DataSource
DBGrid

こんにちは、中野と申します。
いつもお世話になっています。

質問の内容で少し進展がありましたので報告します。
結果から言いますと、解決に至っていません。

テーブルにレコードを挿入する方法として、幾つか私が行った内容を記載します。

<方法その1>
void __fastcall TForm::Button1Click(TObject *Sender)

ClientDataSet->Insert();


void __fastcall TForm::Button2Click(TObject *Sender)

// 挿入したレコードのセルにデータを入力するプログラムを記載


void __fastcall TForm::Button3Click(TObject *Sender)

SQLDataSet->CommandType = ctTable;
SQLDataSet->DbxCommandType = "Dbx.Table";
SQLDataSet->CommandText = TableName; // TableNameは、DBGridで選択しているテーブル名が入ります
ClientDataSet->Edit();
ClientDataSet->Post();
ClientDataSet->ApplyUpdates(-1);
SQLDataSet->CommandType = ctQuery;
SQLDataSet->DbxCommandType = "Dbx.SQL";
SQLDataSet->CommandText = "";


1.テーブル表示後にボタン1で、レコード(行)を挿入
2.挿入したレコードのセルに静的または動的にデータを入力
3.データベースに編集したテーブルをアップデートする。
結果は、テーブルの最終行に挿入したレコードが追加されている状態。
編集中は挿入されている表示ですが、アップデート後にテーブルを再表示するとテーブルの最終行に挿入したレコードが追加されている

<方法その2>
void __fastcall TForm::Button1Click(TObject *Sender)

ClientDataSet->Insert();
ClientDataSet->Post();
ClientDataSet->ApplyUpdates(-1);


1.テーブル表示後に、ボタン1をクリックするとレコードを挿入する。
画面上では挿入している。
データベースにアップデートし、テーブルを再表示すると挿入したレコードは、テーブルの最終行に追加されている。

<方法その3>
void __fastcall TForm::Button1Click(TObject *Sender)

DBGrid->DataSource->DataSet->InsertRecord(ARRAYOFCONST((”(空白)”)));
ClientDataSet->ApplyUpdates(-1);


1.テーブル表示後に、ボタン1をクリックするとレコードを挿入する。
画面上では挿入している。
データベースにアップデートし、テーブルを再表示すると挿入したレコードは、テーブルの最終行に追加されている。

個人的な考えですが、データベース系コンポーネントDBXでは、テーブルにレコードをInsert()挿入する機能がないまたは実装されていないと思っています。
下記はエンバカデロ社のホームページで、「新規レコードの追加と挿入」に関して記載がありますが、内容的には出来ない様な捕らえ方もできます。
http://docwiki.embarcadero.com/RADStudio/XE8/ja/%E6%96%B0%E8%A6%8F%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E8%BF%BD%E5%8A%A0

また、仕様です。と言われたらそれまでですが、もう一つ方法があるので試してみようと思います。

<方法その4>
これから行う予定
テーブルに5行のレコードがあるとし、2行目と3行の間に新規レコードを挿入する。
1.3行以降の全てのレコード情報を別の仮テーブルに退避させる。
2.その後、現行のテーブルより3行目以降のレコード情報を削除する。
3.このとき、現行のテーブルは2行のレコードのみとなります。
4.ここに、Append()命令でテーブル最終行の次にレコードを追加し、アップデートする。
5.次に、退避させた全レコード内容を現行のテーブルに追加させて、アップデートする。


本当は、エクセルの様に行を簡単に挿入できるかと思っていましたが、今の所は全くできていません。

テーブルにレコードを挿入しアップデートしても、レコード挿入位置が変化しない方法
に関してご存知の方いましたらご助言頂けると助かります。
参考になるインターネットサイトや書籍等ございましたら教えて貰えると助かります。

お忙しいところ、よろしくお願いします。

igy kk

Posts: 147
Registered: 9/11/03
Re: ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 31, 2015 12:55 AM   in response to: Nakano Shintaro in response to: Nakano Shintaro
こんなので、どうでしょう?

1.テーブルに 並び順 (1, 2, 3...)を格納するフィールドに用意する。
2.テーブルを表示するとき、その並び順で表示するようにする。
3.ある箇所で挿入したい場合、挿入したい場所以下の並び順フィールドを1ずつ増やしたあと、
データを追加。

1 AAA
2 BBB
3 CCC
4 DDD

BBBとCCCに間に ZZZを挿入する場合、

1 AAA
2 BBB
<= 3 ZZZ 追加
4 CCC
5 DDD
Nakano Shintaro

Posts: 22
Registered: 8/25/04
Re: ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 1, 2015 10:10 PM   in response to: igy kk in response to: igy kk
こんにちは、中野ともうします。
igy kk 様、ご助言ありがとうございます。

こんなので、どうでしょう?

1.テーブルに 並び順 (1, 2, 3...)を格納するフィールドに用意する。
2.テーブルを表示するとき、その並び順で表示するようにする。
3.ある箇所で挿入したい場合、挿入したい場所以下の並び順フィールドを1ずつ増やしたあと、
データを追加。

1 AAA
2 BBB
3 CCC
4 DDD

BBBとCCCに間に ZZZを挿入する場合、

1 AAA
2 BBB
<= 3 ZZZ 追加
4 CCC
5 DDD

igy kk 様のご助言での方法でプログラムを組んでみました。
プログラムを作成し動作させてみましたが、DBGrid上では動いていますが、データベースに登録しテーブルを再表示すると
正常にDBGrid上のデータが登録されていない。

<作成したプログラム>
// テーブル最終行にレコードを追加する
ClientDataSet->Append();
ClientDataSet->Post();
ClientDataSet->ApplyUpdates(-1);

//
TotalRecordNumber = 0;
TotalRecordNumber = ClientDataSet->RecordCount;
//
TotalFieldNumber = 0;
TotalFieldNumber = ClientDataSet->FieldCount;
//
DBGrid->ReadOnly = false;
DummyRecordNum = TotalRecordNumber - CursorRecordNum;

// 現存のレコードをコピーして移動する。次の行に1行だけ移動する。
for (RecordNum = 0; RecordNum < DummyRecordNum ; RecordNum++) {
//
for (FieldNum = 0; FieldNum < TotalFieldNumber - 2; FieldNum++) {
//
InsertFieldNames = "";
InsertFieldNames = DBGrid->Columns->Items[FieldNum]->FieldName;
DummyRecNum = TotalRecordNumber - RecordNum;
// 一時的にセル情報を入れる
ClientDataSet->RecNo = DummyRecNum - 1;
DBGrid->SelectedIndex = FieldNum;
DBGrid->SetFocus();
DummyCelData = "";
DummyCelData = DBGrid->SelectedField->AsString;

// 次のレコードにセル内容をコピーする
ClientDataSet->RecNo = DummyRecNum;
DBGrid->SetFocus();

DBEdit->DataField = InsertFieldNames;
DBEdit->SetFocus();

ClientDataSet->Edit();
DBEdit->Text = "";
DBEdit->Text = DummyCelData;
ClientDataSet->Post();
//
ClientDataSet->ApplyUpdates(-1);
}
}

for (FieldNum = 0; FieldNum < TotalFieldNumber - 2; FieldNum++) {
//
InsertFieldNames = "";
InsertFieldNames = DBGrid->Columns->Items[FieldNum]->FieldName;
//
ClientDataSet->RecNo = CursorRecordNum;
DBGrid->SelectedIndex = FieldNum;
DBGrid->SetFocus();

DBEdit->DataField = InsertFieldNames;
DBEdit->SetFocus();

ClientDataSet->Edit();
DBEdit->Text = "(空白)";
ClientDataSet->Post();
//
ClientDataSet->ApplyUpdates(-1);
}
<作成したプログラムここまで>

DBGrid上では動いていますが、データベースにテーブル内容をアップデートする際、誤った方法で登録している
可能性が高いかと思っています。

今後は、正確にデータベースにテーブル情報をアップデートする方法等を少し学びたいと思います。

ご助言提案等、本当に有難うございました。
また何か解らない事で書き込みをするかも知れませんが、宜しくお願いします。

igy kk

Posts: 147
Registered: 9/11/03
Re: ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 2, 2015 9:06 PM   in response to: Nakano Shintaro in response to: Nakano Shintaro
SQL文で書くとこんな感じかと・・

1.テーブルに 並び順 (1, 2, 3...)を格納するフィールドに用意する。

テーブル名を仮に HOGE_TABLE として、

HOGE_NAME VARCHAR(40)
SNO INTEGER // 並び順を格納

のような感じで、フィールドを用意し、

// テストデータ追加
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('AAA', 1);
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('BBB', 2);
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('CCC', 3);
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('DDD', 4);

2.テーブルを表示するとき、その並び順で表示するようにする。

SELECT SNO, HOGE_NAME FROM HOGE_TABLE ORDER BY SNO;

3.ある箇所で挿入したい場合、挿入したい場所以下の並び順フィールドを1ずつ増やしたあと、データを追加。

SNOが3の位置に挿入したい場合、

// 並び順更新&挿入
UPDATE HOGE_TABLE SET SNO = SNO + 1 WHERE SNO >= 3;
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('ZZZ', 3);
Nakano Shintaro

Posts: 22
Registered: 8/25/04
Re: ClientDataSetのInsertで、挿入されるレコードがランダムにデータベースに登録されてしまう  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 8, 2015 11:03 PM   in response to: igy kk in response to: igy kk
こんにちは、中野です。
igy kk 様、、ご助言ありがとうございます。

例題まで記載してもらい、有難うございます。

SQL文で書くとこんな感じかと・・

1.テーブルに 並び順 (1, 2, 3...)を格納するフィールドに用意する。

テーブル名を仮に HOGE_TABLE として、

HOGE_NAME VARCHAR(40)
SNO INTEGER // 並び順を格納

のような感じで、フィールドを用意し、

// テストデータ追加
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('AAA', 1);
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('BBB', 2);
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('CCC', 3);
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('DDD', 4);

<プログラムを作成してみました>
String SQLInssert;

SQLInssert = "";
SQLInssert = "INSERT INTO " + TableName + "(HOGE_NAME, SNO) VALUES ('AAA', 1)";
// SQL文を実行する
SQLDataSet->CommandText = "";
SQLDataSet->CommandText = SQLInssert;
//
ClientDataSet->Execute();

//
SQLInssert = "";
SQLInssert = "INSERT INTO " + TableName + "(HOGE_NAME, SNO) VALUES ('BBB', 2)";
// SQL文を実行する
SQLDataSet->CommandText = "";
SQLDataSet->CommandText = SQLInssert;
//
ClientDataSet->Execute();

//
SQLInssert = "";
SQLInssert = "INSERT INTO " + TableName + "(HOGE_NAME, SNO) VALUES ('CCC', 3)";
// SQL文を実行する
SQLDataSet->CommandText = "";
SQLDataSet->CommandText = SQLInssert;
//
ClientDataSet->Execute();

//
SQLInssert = "";
SQLInssert = "INSERT INTO " + TableName + "(HOGE_NAME, SNO) VALUES ('DDD', 4)";
// SQL文を実行する
SQLDataSet->CommandText = "";
SQLDataSet->CommandText = SQLInssert;
//
ClientDataSet->Execute();
<ここまで>
TableNameには、テーブル名が入ります。



2.テーブルを表示するとき、その並び順で表示するようにする。

SELECT SNO, HOGE_NAME FROM HOGE_TABLE ORDER BY SNO;

3.ある箇所で挿入したい場合、挿入したい場所以下の並び順フィールドを1ずつ増やしたあと、データを追加。

SNOが3の位置に挿入したい場合、

// 並び順更新&挿入
UPDATE HOGE_TABLE SET SNO = SNO + 1 WHERE SNO >= 3;
INSERT INTO HOGE_TABLE (HOGE_NAME, SNO) VALUES ('ZZZ', 3);

<プログラムを作成してみました その2>
SQLInssert = "UPDATE " + TableNameTable + " SET SNO = SNO + 1 WHERE SNO >= 3";
// SQL文を実行する
SQLDataSet->CommandText = "";
SQLDataSet->CommandText = SQLInssert;
//
ClientDataSet->Execute();

SQLInssert = "";
SQLInssert = "INSERT INTO " + TableNameTable + " (HOGE_NAME, SNO) VALUES ('ZZZ', 3)";
// SQL文を実行する
SQLDataSet->CommandText = "";
SQLDataSet->CommandText = SQLInssert;
//
ClientDataSet->Execute();
<ここまで>

データベースに登録はできる様になりました。

ただ、テーブル再表示後にテーブル内のセルを編集し、編集内容をデータベースに登録する事は出来ません。
エラーメッセージ等は、何も表示していません。
セルを編集後にデータベースへ登録後に、再度、テーブルを表示すると編集する前の状態でした。
私の考えでは、テーブル編集自体がロック状態に陥っている?と思っています。

お忙しい所、ご助言ありがとうございました。
もう少し、データベースのInsert機能に関して調べて見たいと思います。
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02