在MySQL主 - 详细信息表对

时间:2015-08-11 07:20:28

标签: mysql delphi query-optimization master-detail

我的项目中有一个单元,用于在用户之间进行消息交换。为此,我使用了两个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

那是主人。它包含有关发件人,标题,邮件正文等信息和

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

作为发送消息的用户的信息,打开消息的日期/时间等的详细信息(其余信息由触发器设置)以下代码正常工作并发送消息。

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;

2 个答案:

答案 0 :(得分:3)

为了提高效率,请使用多行INSERT:

INSERT INTO table2 
    (id, x)
    VALUES
    (@last_id,"newVal_1"),
    (@last_id,"newVal_2"),
    (@last_id,"newVal_3");

答案 1 :(得分:2)

使用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");

这样您只需要一次调用服务器