在 MySQL master-detail table 对中插入记录的最佳方式
Optimal way to insert records in MySQL master-detail table pair
我的项目中有一个单元执行用户之间的消息交换。为此,我使用了两个 MySQL 表:
CREATE TABLE `tmessages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`header` varchar(100) DEFAULT NULL,
`body` text,
...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
那就是大师。它包含有关发件人、header、body 消息等的信息以及
CREATE TABLE `tmessage_recipients` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`idmessage` int(10) unsigned NOT NULL DEFAULT '0',
`idstuff_recipient` int(10) unsigned NOT NULL DEFAULT '0',
...,
PRIMARY KEY (`id`,`idmessage`,`idstuff_recipient`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
作为消息发送到的用户的详细信息,date/time 打开消息等(其余信息由触发器设置)以下代码正常工作并发送消息.
var
s: string;
idmessage: longword;
i: Word;
...
s := 'INSERT INTO `tmessages` SET ' + '`header`=' + QuotedStr(Edit12.Text) +
', ' + '`body`=' + QuotedStr(Memo3.Text);
Hdm1.FDConnection1.ExecSQL(s);
idmessage := Hdm1.FDConnection1.ExecSQLScalar('SELECT `id` FROM `tmessages` '
+ 'WHERE `header`=' + QuotedStr(Edit12.Text) + 'AND `body`=' +
QuotedStr(Memo3.Text) + ' ORDER BY `id` DESC LIMIT 1');
for i := 0 to ListBox3.Count - 1 do
begin
s := 'INSERT INTO `tmessage_recipients` SET ' + '`idmessage`=' +
inttostr(idmessage) + ', ' + '`idstuff_recipient`=' +
inttostr(ListBox3.ItemByIndex(i).Tag);
Hdm1.FDConnection1.ExecSQL(s);
end;
但我认为这不是最佳选择,因为我必须先获取 idmessage。如何优化程序并使其更可靠? Hdm1.FDConnection1.ExecSQL()
?
一次调用可以插入吗
编辑
根据@Alex Tartan 和@whosrdaddy 的评论,我得出了这样的结论。这是最优方法吗?或者我需要改变什么?
s:= 'INSERT INTO `tmessages` (`header`,`body`) VALUES(:p1, :p2);'#13#10 +
'SET @last_id := (SELECT LAST_INSERT_ID());';
for i := 0 to ListBox3.Count - 1 do
s := s + #13#10'INSERT INTO `tmessage_recipients` (`idmessage`,`idstuff_recipient`)'
+ ' VALUES(@last_id,' + inttostr(ListBox3.ItemByIndex(i).Tag) + ');';
Hdm1.FDConnection1.ExecSQL(s, [Edit12.Text, Memo3.Text]);
编辑 2
在@kobik 的提议下,我得出了以下结论:
s:= 'INSERT INTO `tmessages` (`header`,`body`) VALUES(:p1, :p2);'#13#10 +
'SET @last_id := (SELECT LAST_INSERT_ID());';
for i := 0 to ListBox3.Count - 1 do
s := s + #13#10'INSERT INTO `tmessage_recipients` (`idmessage`,`idstuff_recipient`)'
+ ' VALUES(@last_id,' + inttostr(ListBox3.ItemByIndex(i).Tag) + ');';
HDM1.FDQViaFDTransaction.Transaction.StartTransaction;
try
HDM1.FDQViaFDTransaction.ExecSQL(s, [Edit12.Text, Memo3.Text]);
HDM1.FDQViaFDTransaction.Transaction.Commit;
except
HDM1.FDQViaFDTransaction.Transaction.Rollback;
end;
编辑 3
在@Rick-James 的宝贵建议下,代码被转换为以下...
s := 'INSERT INTO `tmessages` (`header`,`body`) VALUES(:p1, :p2);'#13#10 +
'SET @last_id := (SELECT LAST_INSERT_ID());';
s := s + #13#10'INSERT INTO `tmessage_recipients` ' +
'(`idmessage`,`idstuff_recipient`)'#13#10'VALUES';
for i := 0 to ListBox3.Count - 1 do
s := s + #13#10'(@last_id,' + inttostr(ListBox3.ItemByIndex(i).Tag) + '),';
s[High(s)] := ';';
Hdm1.FDQViaFDTransaction.Transaction.StartTransaction;
try
Hdm1.FDQViaFDTransaction.ExecSQL(s, [Edit12.Text, Memo3.Text]);
Hdm1.FDQViaFDTransaction.Transaction.Commit;
ShowMessage('Message sent.');
Button10Click(self);
except
Hdm1.FDQViaFDTransaction.Transaction.Rollback;
end;
使用一个mysql变量:
INSERT INTO table1 (id,value) VALUES(1,'test');
SET @last_id := (SELECT LAST_INSERT_ID());
INSERT INTO table2 (id,colName) VALUES(@last_id,"newVal_1");
...
INSERT INTO table2 (id,colName) VALUES(@last_id,"newVal_n");
这样你只需要调用一次服务器
为了提高效率,使用多行插入:
INSERT INTO table2
(id, x)
VALUES
(@last_id,"newVal_1"),
(@last_id,"newVal_2"),
(@last_id,"newVal_3");
我的项目中有一个单元执行用户之间的消息交换。为此,我使用了两个 MySQL 表:
CREATE TABLE `tmessages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`header` varchar(100) DEFAULT NULL,
`body` text,
...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
那就是大师。它包含有关发件人、header、body 消息等的信息以及
CREATE TABLE `tmessage_recipients` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`idmessage` int(10) unsigned NOT NULL DEFAULT '0',
`idstuff_recipient` int(10) unsigned NOT NULL DEFAULT '0',
...,
PRIMARY KEY (`id`,`idmessage`,`idstuff_recipient`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
作为消息发送到的用户的详细信息,date/time 打开消息等(其余信息由触发器设置)以下代码正常工作并发送消息.
var
s: string;
idmessage: longword;
i: Word;
...
s := 'INSERT INTO `tmessages` SET ' + '`header`=' + QuotedStr(Edit12.Text) +
', ' + '`body`=' + QuotedStr(Memo3.Text);
Hdm1.FDConnection1.ExecSQL(s);
idmessage := Hdm1.FDConnection1.ExecSQLScalar('SELECT `id` FROM `tmessages` '
+ 'WHERE `header`=' + QuotedStr(Edit12.Text) + 'AND `body`=' +
QuotedStr(Memo3.Text) + ' ORDER BY `id` DESC LIMIT 1');
for i := 0 to ListBox3.Count - 1 do
begin
s := 'INSERT INTO `tmessage_recipients` SET ' + '`idmessage`=' +
inttostr(idmessage) + ', ' + '`idstuff_recipient`=' +
inttostr(ListBox3.ItemByIndex(i).Tag);
Hdm1.FDConnection1.ExecSQL(s);
end;
但我认为这不是最佳选择,因为我必须先获取 idmessage。如何优化程序并使其更可靠? Hdm1.FDConnection1.ExecSQL()
?
编辑
根据@Alex Tartan 和@whosrdaddy 的评论,我得出了这样的结论。这是最优方法吗?或者我需要改变什么?
s:= 'INSERT INTO `tmessages` (`header`,`body`) VALUES(:p1, :p2);'#13#10 +
'SET @last_id := (SELECT LAST_INSERT_ID());';
for i := 0 to ListBox3.Count - 1 do
s := s + #13#10'INSERT INTO `tmessage_recipients` (`idmessage`,`idstuff_recipient`)'
+ ' VALUES(@last_id,' + inttostr(ListBox3.ItemByIndex(i).Tag) + ');';
Hdm1.FDConnection1.ExecSQL(s, [Edit12.Text, Memo3.Text]);
编辑 2
在@kobik 的提议下,我得出了以下结论:
s:= 'INSERT INTO `tmessages` (`header`,`body`) VALUES(:p1, :p2);'#13#10 +
'SET @last_id := (SELECT LAST_INSERT_ID());';
for i := 0 to ListBox3.Count - 1 do
s := s + #13#10'INSERT INTO `tmessage_recipients` (`idmessage`,`idstuff_recipient`)'
+ ' VALUES(@last_id,' + inttostr(ListBox3.ItemByIndex(i).Tag) + ');';
HDM1.FDQViaFDTransaction.Transaction.StartTransaction;
try
HDM1.FDQViaFDTransaction.ExecSQL(s, [Edit12.Text, Memo3.Text]);
HDM1.FDQViaFDTransaction.Transaction.Commit;
except
HDM1.FDQViaFDTransaction.Transaction.Rollback;
end;
编辑 3
在@Rick-James 的宝贵建议下,代码被转换为以下...
s := 'INSERT INTO `tmessages` (`header`,`body`) VALUES(:p1, :p2);'#13#10 +
'SET @last_id := (SELECT LAST_INSERT_ID());';
s := s + #13#10'INSERT INTO `tmessage_recipients` ' +
'(`idmessage`,`idstuff_recipient`)'#13#10'VALUES';
for i := 0 to ListBox3.Count - 1 do
s := s + #13#10'(@last_id,' + inttostr(ListBox3.ItemByIndex(i).Tag) + '),';
s[High(s)] := ';';
Hdm1.FDQViaFDTransaction.Transaction.StartTransaction;
try
Hdm1.FDQViaFDTransaction.ExecSQL(s, [Edit12.Text, Memo3.Text]);
Hdm1.FDQViaFDTransaction.Transaction.Commit;
ShowMessage('Message sent.');
Button10Click(self);
except
Hdm1.FDQViaFDTransaction.Transaction.Rollback;
end;
使用一个mysql变量:
INSERT INTO table1 (id,value) VALUES(1,'test');
SET @last_id := (SELECT LAST_INSERT_ID());
INSERT INTO table2 (id,colName) VALUES(@last_id,"newVal_1");
...
INSERT INTO table2 (id,colName) VALUES(@last_id,"newVal_n");
这样你只需要调用一次服务器
为了提高效率,使用多行插入:
INSERT INTO table2
(id, x)
VALUES
(@last_id,"newVal_1"),
(@last_id,"newVal_2"),
(@last_id,"newVal_3");