在单个查询中更新第一个 table 中的行并在第二个 table 中插入一行

Update row in first table and insert a row into a second table in a single query

我正在尝试弄清楚如何在更新第二个 table 中的特定字段时将行插入 table。

假设我有 table 1 (dif):

CREATE TABLE dif
(
    Position INT(10) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
    pKey SMALLINT(3) UNSIGNED NOT NULL,
    Number SMALLINT(3) UNSIGNED DEFAULT 0 NOT NULL
);

ALTER TABLE dif
ADD CONSTRAINT dif_article_pKey_fk
FOREIGN KEY (pKey) REFERENCES article (pKey) ON UPDATE CASCADE;

和table 2 (article):

CREATE TABLE IF NOT EXISTS article (
  pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
  Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
  Number SMALLINT NOT NULL DEFAULT 0
  PRIMARY KEY (pKey)
);

table 文章填充了一些数据,应该只更新。 Table "dif"开头是空的。所以,假设我正在像这样更新 "article" 上的字段:

UPDATE article SET pKey = 15, Name = SomeName,  Number = 22 WHERE pKey=15;

我能否以某种方式将 UPDATE 查询与此结合起来?

INSERT  INTO  dif (pKey, Number) VALUES (15, 12);

“12”是 "article.Number" 更新前后的差异。

不,但是您可以创建一个存储过程来执行这两项操作,然后在一条语句中执行它。

create procedure GiveThisABetterName
(
    in pKey int,
    in newNumber int,
    in currentNumber int,
    in newName varchar(100)
)
begin
    update 
        article 
    set 
        Name = newName, Number = newNumber 
    where 
        pKey = pKey;

    insert into dif (pKey, Number) values (pKey, newNumber);
end

我的 mysql 语法生锈了,但应该差不多了。然后当你想执行它的时候:

call GiveThisABetterName(12, 15, 22, 'Some Name');

编辑:再次阅读您的问题后,在我看来,您正试图让您的数据模型跟踪审计信息,而这些审计信息并未设置为自然适应。你能控制模型吗?如果是这样,请考虑这样的事情(请参阅 here 以下内容的工作示例):

CREATE TABLE IF NOT EXISTS article (
  pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
  Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
  PRIMARY KEY (pKey)
);

CREATE TABLE ArticleNumbers
(
    Counter int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    pKey SMALLINT(3) UNSIGNED NOT NULL,
    Number SMALLINT(3) DEFAULT 0 NOT NULL,
    Difference SMALLINT(3)
);

ALTER TABLE ArticleNumbers
    ADD CONSTRAINT ArticleNumbers_article_pKey_fk
        FOREIGN KEY (pKey) REFERENCES article (pKey) ON UPDATE CASCADE;

也许添加一些视图使事情变得更容易:

CREATE VIEW GroupedArticleNumbers
as
select pKey, max(Counter) as Counter
from ArticleNumbers
group by pKey;

CREATE VIEW CurrentArticles 
as 
select article.pKey, article.Name, numbers.Number, numbers.Difference 
from article 
left outer join GroupedArticleNumbers filter on article.pKey = filter.pKey
left outer join ArticleNumbers numbers on filter.Counter = numbers.Counter;

由于您现在可以从基本记录中单独跟踪号码,但仍然可以轻松确定当前号码是多少,因此您现在可以结合更新和插入语句功能。见下文。

首先,一些测试数据:

insert into article (Name) values ('Test');
insert into ArticleNumbers (pKey, Number, Difference) values (1, 10, null);
insert into ArticleNumbers (pKey, Number, Difference) select 1, 20, 20 - Number from CurrentArticles where pKey = 1;
insert into ArticleNumbers (pKey, Number, Difference) select 1, 50, 50 - Number from CurrentArticles where pKey = 1;
insert into ArticleNumbers (pKey, Number, Difference) select 1, 15, 15 - Number from CurrentArticles where pKey = 1;

看到设置模式的开销已经完成后效果如何?

获取我们创建的文章的当前编号:

select * from currentarticles where pKey = 1

获取该文章的历史记录:

select * from article
left outer join articlenumbers on article.pkey = articlenumbers.pkey
order by counter asc

如果您愿意弄乱您的数据模型,您可以使用存储过程的替代方法。

或者,如果您想按照 @Jonathan Leffler 的建议使用触发器,则类似这样的方法应该可行:

CREATE TABLE article (
 pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
  Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
  Number SMALLINT(3) DEFAULT 0 NOT NULL,
  PRIMARY KEY (pKey)
);

CREATE TABLE ArticleNumbers
(
    Counter int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    pKey SMALLINT(3) UNSIGNED NOT NULL,
    Number SMALLINT(3) DEFAULT 0 NOT NULL,
    Difference SMALLINT(3)
);

delimiter $
create trigger tr_u_article
before update on article
for each row
begin
  insert into ArticleNumbers (pKey, Number, Difference) select old.pKey,     new.Number, new.Number - old.Number
  end;
delimiter ;