2016-07-09 12 views
-1

Ich versuche herauszufinden, wie Sie eine Zeile in eine Tabelle zum Aktualisieren eines bestimmten Feldes in der zweiten Tabelle einfügen.Zeile in erster Tabelle aktualisieren und eine Zeile in eine zweite Tabelle in einer einzigen Abfrage einfügen

Lassen Sie uns sagen, ich habe Tabelle 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; 

und Tabelle 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) 
); 

Der Tabellenartikel ist mit einigen Daten gefüllt und sollte nur aktualisiert werden. Tabelle "dif" ist am Anfang leer. Also, lassen Sie uns sagen, dass ich die Felder bin Aktualisierung auf „Artikel“ wie folgt aus:

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

Kann ich irgendwie die UPDATE-Abfrage mit diesem kombinieren?

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

Die "12" ist der Unterschied zwischen der "article.Number" vor und nach UPDATE.

+1

nur eine gespeicherte Prozedur machen, die eine Transaktion hat. Für den Aufrufer ist es eine Abfrage – Drew

+1

Müssen Sie [einen Trigger erstellen] (https://dev.mysql.com/doc/refman/5.7/en/create-trigger.html) auf der Tabelle aktualisiert werden, wo die Aktion ist in die andere Tabelle einzufügen? –

Antwort

1

Nein, aber Sie können eine gespeicherte Prozedur erstellen, die diese beiden Dinge ausführt und sie dann in einer einzigen Anweisung ausführt.

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 

Meine MySQL-Syntax ist rostig, aber das sollte in der Nähe sein. Dann, wenn Sie wollen, um es auszuführen:

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

EDIT: Nach der Frage erneut zu lesen, scheint es mir, dass Sie versuchen, Ihr Datenmodell Spur Audit-Informationen zu machen, dass es einfach nicht natürlich aufnehmen einzurichten. Haben Sie die Kontrolle über das Modell? Wenn ja, sollten Sie so etwas wie dies (siehe here für ein funktionierendes Beispiel von dem, was unten):

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; 

Vielleicht ein paar Ansichten hinzufügen, um die Dinge einfacher zu machen:

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; 

Da Sie die Nummer separat verfolgen Aus dem Basisdatensatz können Sie jetzt aber noch leicht ermitteln, um welche aktuelle Zahl es sich handelt, Sie können nun Ihre Update- und Insert-Statement-Funktionalität kombinieren. Siehe unten.

Zunächst einige Testdaten:

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; 

Sehen Sie, wie schön, dass das Schema der Einrichtung, sobald den Kopf klappt getan worden?

Um die aktuelle Nummer für den Artikel erhalten wir erstellt:

select * from currentarticles where pKey = 1 

Um die Anzahl der Geschichte für diesen Artikel zu erhalten:

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

Wenn Sie zu Chaos mit Ihrem Datenmodell bereit sind, Sie können eine Alternative zu gespeicherten Prozeduren haben.

Alternativ, wenn Sie Trigger verwenden möchten als @Jonathan Leffler vorgeschlagen, so etwas wie dies funktionieren sollte:

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 ; 
+1

Danke für die Semikola, Fremder! –

+0

Er möchte vielleicht das Netz berechnet, aber die Frage ist nicht klar, wie das durchgeführt wird (prev Wert, null in 0 umgewandelt, etc etc) – Drew

+0

Danke @ S.C. Leider würde das Ändern des Tabellendesigns zu viele Dinge verändern. Der Auslöser ist, dass ich tatsächlich gebraucht habe. – 0xbadc0de

Verwandte Themen