# MySQL - Wert aus vorheriger Zeile übernehmen und einfügen



## Max-Berater (10. Februar 2022)

Ich möchte gerne die Rechnungsnummer RE90392022die in beiden Zeilen vorhanden in die dritte Zeile (leer) einfügen, wenn in Zeile x Wert y vorhanden ist. Wie sage ich dem System, dass er den Wert der vorherigen Zeile nehmen soll?


----------



## Yaslaw (10. Februar 2022)

Grundsätzlich gibt es in einer DB nicht "Die Zeile davor". Das ist je nach Sortierung und Filterung unterschiedlich. Die Daten siond auch nicht wie in einem Excel in einer festen Reihenfolge gespeichert.

In einem SQL, kannst du aber auf einen Wert der Ausgabezeile davor zugreifen. In MySQL ist `@varname:=value` die formel. Zudem werden die Ausgabefelder in der angegeben Reihenfolge abgearbeitet. Sprich, du kannst in Spalte 3 auf die Spalten 1 und 2 zugreifen.

```
select
    t.my_value,
    -- Variable ausgeben
    @prev_value as prev_value,
    -- und danach die Variable neu setzen
    @prev_value := t.my_value as save_for_next_row
from my_table t
order by t.my_sort_field
```
und wenn du die hilfsspalte nicht sehen willst.

```
select my_value, prev_value
from (
    select
        t.my_value,
        @prev_value as prev_value,
        @prev_value := t.my_value as save_for_next_row
    from my_table t
    order by t.my_sort_field
)
```


----------



## Zvoni (11. Februar 2022)

Yaslaw hat gesagt.:


> Grundsätzlich gibt es in einer DB nicht "Die Zeile davor". Das ist je nach Sortierung und Filterung unterschiedlich. Die Daten siond auch nicht wie in einem Excel in einer festen Reihenfolge gespeichert.


Doch, gibt es.
Nennt sich LAG-Funktion
MySQL LAG() Function Explained By Practical Examples
und für "Die Zeile danach" gibt es die LEAD-Funktion
Wobei besssere Bezeichnungen
"Wenn in Zeile Darunter der Wert aus Zeile Darüber gezeigt werden soll" (LAG-Funktion)
"Wenn in Zeile Darüber der Wert aus Zeile Darunter gezeigt werden soll" (LEAD-Funktion)
sind

Ungetestet müsste es irgendwie so gehen:

```
SELECT
EinFeld,
COALESCE(RENummer,LAG(RENummer),'Nix gefunden') AS MeineRechnung
FROM
IrgendeineTabelle
ORDER BY
EinFeld,
RENummer
```

EDIT: Habs mal in SQLite getestet
Das war meine Datenbasis

IDDescription1Job12Job23Job34Job456Job67Job789Job9


```
SELECT
ID,
coalesce(Description, LAG(Description) OVER(ORDER BY ID),'Sorry') AS Description
FROM Jobs ORDER BY ID
```
Ergebnis:

1Job12Job23Job34Job45Job46Job67Job78Job79Job9


Das Einfügen (UPDATE) ist dann ein simples UPDATE-Statement gejoint auf o.g. SELECT, mit Prüfung auf IS NULL im Original-Satz.

Ungetestet

```
UPDATE Jobs As J1
SET J1.Description=S1.Vorher
FROM
(SELECT ID,coalesce(Description, LAG(Description) OVER(ORDER BY ID),'Sorry') As Vorher FROM Jobs ORDER BY ID) As S1
WHERE
J1.ID=S1.ID AND J1.Description IS NULL
```


----------



## Yaslaw (11. Februar 2022)

Wieder was dazugelernt.
Aber dass es keine fixe Reihenfolge gibt, das stimmt. Darum muss man im LAG ja den ORDER BY mitgeben, damit die Methode den vorherigen Datensatz ermitteln kann.

Hier habe ich eine nette ANleitung für LAG in MySQL gefunden: MySQL LAG() Function Explained By Practical Examples


----------



## Zvoni (11. Februar 2022)

Yaslaw hat gesagt.:


> Wieder was dazugelernt.
> Aber dass es keine fixe Reihenfolge gibt, das stimmt. Darum muss man im LAG ja den ORDER BY mitgeben, damit die Methode den vorherigen Datensatz ermitteln kann.
> 
> Hier habe ich eine nette ANleitung für LAG in MySQL gefunden: MySQL LAG() Function Explained By Practical Examples


Faustregel: Der Order By innerhalb der LAG-Funktion ist derselbe wie der ORDER BY des zugrundeliegenden Selects (kann ja eingebettet sein)

Dir ist klar, dass dein Link derselbe wie meiner oben ist? 

EDIT: Das funktioniert natürlich nur, wenn echte "NULL"'s in den Feldern stehen, sonst greift COALESCE ins Leere. Ansonten vielleicht mit CASE WHEN Trim(Description)='' THEN blabablbabla.
Müsste ich aber testen


----------



## Yaslaw (11. Februar 2022)

Zvoni hat gesagt.:


> Dir ist klar, dass dein Link derselbe wie meiner oben ist?


Nö, hab dein Beitrag überflogen und gesehen LAG+Test in SQLLIght. Dann ab zu google und den Befehl gesucht - Sorry


----------



## Max-Berater (16. Februar 2022)

Danke für Eure ausführlichen Anleitungen. Ich hab gestern mal gebastelt aber ohne pos. Resultat.

In Belegfeld 1 Reihe 3 soll die Rechnungsnummer RE91502022 rein, damit wir wissen, dass dieses zusammen gehört.


----------



## Yaslaw (16. Februar 2022)

Zeiug mal dein Versuch


----------



## Max-Berater (16. Februar 2022)

```
select my_value, prev_value
from (
    select
        t.`Belegfeld 1`,
        @prev_value as prev_value,
        @prev_value := t.`Beleginfo 1` as save_for_next_row
    from RECHNUNGEN
    order by t.`Belegfeld 2`
```


----------



## Yaslaw (16. Februar 2022)

Wenn man Beispiele übernimmt, sollte man versuchen sie zu verstehen und dann an die eigenen Gegebenheiten anzupassen. Dann sollte man die Fehlermeldungen anschaen. Ich bin sicher, dieses SQL Statement wirft ein Fehler, da das Feld my_value nicht bekannt ist.
Aber ich würde diese Variante eh verwerfen und auf LAG setzen, dass genau dazu da ist.

Beipieldaten der Tabelle t_2124206

```
BELEGFELD_1 | BELEGFELD_2 | BUCHUNGTEXT
RE1234      | B1          | TEST
RE1234      | B1          | TEST 2
            | B1          | TEST 3
RE456       | B2          |
            | B2          |
```

SQL

```
SELECT
    IFNULL(
        t.BELEGFELD_1, 
        LAG(t.BELEGFELD_1, 1) 
            over (
                -- Gruppieren über BELEGFELD_2
                PARTITION BY t.BELEGFELD_2    
                -- Absteigend sortiert BELEGFELD_1
                ORDER BY t.BELEGFELD_1 DESC
            )
    ) AS NEW_BELEGFELD_1,
    t.*
FROM t_2124206 t
```

Resultat

```
NEW_BELEGFELD_1 | BELEGFELD_1 | BELEGFELD_2 | BUCHUNGTEXT
RE1234          | RE1234      | B1          | TEST 2
RE1234          | RE1234      | B1          | TEST
RE1234          |             | B1          | TEST 3
RE456           | RE456       | B2          |
RE456           |             | B2          |
```


----------



## Max-Berater (16. Februar 2022)

Ich nutz Heidi sql da bekomme ich überhaupt nie eine Fehlermeldung. Ich versuche es in mal mit einem anderen Programm, was hierfür ggf besser geeignet ist


----------



## Yaslaw (16. Februar 2022)

Mein Beispiel ist mit HEide-SQL geschrieben und getestet. Das geht.
Aber bring doch mal die Fehlermeldung.
Und du hast sicher den Beispielcode an deine DB angepasst? Bei mir heisst die Tabelle und die Spalten anders als bei dir.


----------



## Zvoni (16. Februar 2022)

Max-Berater hat gesagt.:


> Ich nutz Heidi sql da bekomme ich überhaupt nie eine Fehlermeldung. Ich versuche es in mal mit einem anderen Programm, was hierfür ggf besser geeignet ist


Es ist ein MySQL-Server.
ich benutze MySQL-Workbench
nie was anderes benutzt…..


----------



## Yaslaw (16. Februar 2022)

Und Heidi-SQL gibt auch fehler aus. Als Popup und in der Consolenausgabe


----------



## Max-Berater (17. Februar 2022)

Ich habe heute einmal versucht das oben genannte nachzubauen und zu verstehen. Ich kriege jedoch stets eine Fehlermeldung, wie unten zu sehen ist.
Was mache ich bloß falsch.





11:25:16    SELECT     IFNULL(         t.BELEGFELD_1,          LAG(t.BELEGFELD_1, 1)              over (                 -- Gruppieren über BELEGFELD_2                 PARTITION BY t.BELEGFELD_2                     -- Absteigend sortiert BELEGFELD_1                 ORDER BY t.BELEGFELD_1 DESC             )     ) AS NEW_BELEGFELD_1,     t.* FROM t_2124206 t    Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(                 -- Gruppieren über BELEGFELD_2                 PARTITION BY t' at line 5    0.032 sec


----------



## Yaslaw (17. Februar 2022)

Lade mal die neuste Version von Heidi-SQL herunter. Und welche Version von MySQL Server hast du? Ich denke, du solltest da Version 8 haben, damit LAG funktioniert.


----------



## Zvoni (17. Februar 2022)

*GROWL*
LAG/LEAD gibt's erst ab MySQL8.0 (sowie auch die anderen WINDOW-Functions --> ROW_NUMBER usw.)
Sorry, wusste ich aber auch nicht

Und es ist MySQL 5.7 aus vergangen Threads des OP


----------



## Max-Berater (17. Februar 2022)

HEIDI SQL ist bei mir stets aktuell. Workbench hab ich gerade aktualisiert.  Ich schaue mal auf dem Server nach


----------



## Max-Berater (17. Februar 2022)




----------



## Zvoni (17. Februar 2022)

Das Workbench hat Version 8.0, nicht dein SERVER --> Der ist 5.7

Für LAG/LEAD brauchste MySQL-Server 8.0

Würde mir eh mal Gedanken über ein Upgrade machen

MySQL-Server 5.7 EOL=Oktober 2023
EOL MySQL | End of Life (EOL) | Oracle Corporation | Lifecycle


----------



## Max-Berater (17. Februar 2022)

Hast Recht.


----------



## Yaslaw (17. Februar 2022)

Ok, ohne LAG für Vrsion 5.x

Zuerst pro Gruppierung den MAX-Wert bestimmen.

```
SELECT    
           MAX(tm.BELEGFELD_1) AS DEFAULT_BF_1,
           tm.BELEGFELD_2   
        FROM     t_2124206 tm
        GROUP BY tm.BELEGFELD_2
```
Und diesen dann wieder mit der Quelle verknüpfen. Somit kannst du im Null-Fall auf den Wert zurückgreifen

```
SELECT
    IFNULL(t.BELEGFELD_1, t_default_bf.DEFAULT_BF_1) AS NEW_BELEGFELD_1,
    t.*
FROM t_2124206 t
    INNER JOIN (
        SELECT    
           MAX(tm.BELEGFELD_1) AS DEFAULT_BF_1,
           tm.BELEGFELD_2   
        FROM     t_2124206 tm
        GROUP BY tm.BELEGFELD_2
    ) t_default_bf ON t.BELEGFELD_2 = t_default_bf.BELEGFELD_2
```


----------



## Zvoni (17. Februar 2022)

Wie gesagt, denk mal über ein Upgrade nach.
Aus diversen deiner früheren Threads war der erste Lösungsansatz meist einer, welcher MySQL8.0 benötigte.

Mit MySQL5.7 mussten wir dann eher durch brennende Reifen springen, dunkle Messen abhalten, und unverständliche Beschwörungsformeln murmeln

EDIT: und siehe da: Yaslaw bestätigt es sogar.
Vergleich mal das Getöse mit der Lösung mit der LAG-Funktion


----------



## Max-Berater (17. Februar 2022)

Habe gerade all-inkl. angerufen. Es gibt das Maria DB Version 10 - ich werde dorthin umziehen und nochmals testen


----------



## Zvoni (17. Februar 2022)

LAG
Es sollte aber min. MariaDB 10.2 sein


----------



## Max-Berater (17. Februar 2022)

Ist wohl 10.5 lt Aussage.


----------



## Zvoni (17. Februar 2022)

Max-Berater hat gesagt.:


> Ist wohl 10.5 lt Aussage.


Na dann....


----------



## Max-Berater (17. Februar 2022)

Ich berichte Euch. Danke schon mal für die tolle Unterstützung


----------



## Max-Berater (18. Februar 2022)

Es ist vollbracht. Werde gleich testen und berichten.


----------



## Max-Berater (18. Februar 2022)

Das Ergebnis ist schon deutlich besser als gestern und es gibt keine Fehlermeldung mehr. Aber er setzt leider nicht die fehlenden Werte


----------



## Zvoni (18. Februar 2022)

Ist es wieder das Thema NULL vs. '' (blanker Text) wie wir es schon vor 2-3 Wochen hatten?
Heidi SQL - Tabellenzeilen löschen wenn Spalte leer

SELECT IFNULL(CASE WHEN TRIM(t.BELEGFELD_1)='' THEN NULL ELSE t.BELEGFELD_1 END, LAG(blablablabla


----------



## Max-Berater (18. Februar 2022)

Fehler gefunden, habe die Felder NULL deklariert. Läuft nun.
Besten Dank für Eure Unterstützung.


----------



## Max-Berater (18. Februar 2022)

Klappt nun wie gewollt. Muss nur noch versuchen das NEW_Belegfeld_1 in die Tabelle zu schreiben und dann gegen das Belegfeld 1 zu ersetzen.


----------



## Zvoni (18. Februar 2022)

Müsste doch ein simples
UPDATE Tabelle T1
SET T1.BELEGFELD_1= T2.NEW_BELEGFELD_1
FROM /* Hier die Abfrage mit der Lag funktion*/ AS T2
WHERE /*Hier die Bedingungen */ T1.ID=T2.ID
sein
nicht getestet.
musst natürlich die ID in der Abfrage mitliefern (oder was auch immer dein Primär Schlüssel ist)


----------



## Max-Berater (18. Februar 2022)

Ich versuche es morgen weiter. Heute erziele ich keine brauchbaren Ergebnisse mehr.


----------



## Sempervivum (19. Februar 2022)

Meine Kenntnisse reichen leider nicht aus, um den Verlauf dieser Diskussion und die Beispiele vollständig zu verstehen  aber ich frage mich, ob es nicht einfacher geht. Meine Überlegung: Wie @Yaslaw eingangs schrieb, ist die Reihenfolge der Datensätze zunächst mal undefiniert und wird erst durch eine Sortierung hergestellt. Sehe ich mir die Beispiele an, die @Max-Berater gepostet hat, scheint mir, dass Belegfeld2 das einzige Kriterium ist, um zusammen gehörende Datensätze zu ermitteln. Sofern das zutrifft, kann man den fehlenden Wert in Belegfeld1 so auffüllen:

```
UPDATE buchungen as b1 set Belegfeld1=(
    SELECT DISTINCT Belegfeld1 FROM buchungen as b2
    WHERE b2.Belegfeld1 IS NOT NULL
        AND b1.Belegfeld2=b2.Belegfeld2
    )
```
Meine Testtabelle, der Einfachheit halber mit Nummern statt Strings:

```
--
-- Tabellenstruktur für Tabelle `buchungen`
--

CREATE TABLE `buchungen` (
  `id` int(11) NOT NULL,
  `Belegfeld1` int(11) DEFAULT NULL,
  `Belegfeld2` int(11) DEFAULT NULL,
  `Skonto` varchar(50) DEFAULT NULL,
  `Buchungstext` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Daten für Tabelle `buchungen`
--

INSERT INTO `buchungen` (`id`, `Belegfeld1`, `Belegfeld2`, `Skonto`, `Buchungstext`) VALUES
(1, 100001, 194, 'Latlux', 100001),
(2, 100002, 195, 'Lotlux', 100002),
(3, 100003, 196, 'Lotlux', 100003),
(4, 100003, 196, 'Greenlam', 100003),
(5, 100002, 195, 'Fintone', 100002),
(6, 100000, 103, 'Bitwolf', 100000),
(7, 100001, 194, 'Ventosanzap', 100001),
(8, NULL, 195, 'Overhold', 999999),
(9, NULL, 196, 'Y-find', 999999),
(10, NULL, 194, 'Fintone', 999999);
```


----------



## Max-Berater (20. Februar 2022)

Werde es nochmals versuchen mit den hier geposteten Ansätzen.


----------



## Max-Berater (22. Februar 2022)

Ich muss leider erstmal kapitulieren. Habe versucht es nachzuvollziehen, aber ich  glaube es fehlt mir einfach noch das Wissen hierzu das alles zu bewerkstelligen.


----------



## Zvoni (22. Februar 2022)

Wie lautet dein Primärschlüssel für die Tabelle?
kann dir morgen glaube ich dann nen code zusammensetzen


----------



## Max-Berater (22. Februar 2022)

SELECT IFNULL(CASE WHEN TRIM(t.`Belegfeld 1`)='' THEN NULL ELSE t.`Belegfeld 1` END,
        LAG(t.`Belegfeld 1`, 1) 
            over (
                -- Gruppieren über BELEGFELD_2
                PARTITION BY t.`Beleginfo - Inhalt 4`  
                -- Absteigend sortiert BELEGFELD_1
                ORDER BY t.`Belegfeld 1` DESC
            )
    ) AS NEU_BELEGFELD_1,
    t.*


FROM DATEV t;

Klappt so wie gewollt - Nur ich habe zu Beginn der Tabelle das Feld NEU_BELEGFELD_1. Dier Inhalt dieser Spalte NEU_BELEGFELD_1 müsste in die Spalte t.`Belegfeld 1` übernommen werden und NEU_BELEGFELD_1 wieder entfernt werden. 

Mein Gedanke war nun die, nach dem Ausführen des Codes die angezeigte Ausgabe in einer Tabelle zb. DATEV_neu zu speichern und im Nachgang anhand Belegfeld 2 als Primärschlüssel der beiden Tabellen vorhanden ist die Abfrage zu gestalten. Leider finde ich keinen rechten Ansatz.


----------



## Zvoni (22. Februar 2022)

Hat die Tabelle DATEV einen Primärschlüssel? ID oder irgendwas


----------



## Max-Berater (22. Februar 2022)

Nein leider nicht. Ich habe schon in anderen Tabellen gesucht aber nichts wo man sagen könnte hieran matche ich die Daten


----------



## Sempervivum (22. Februar 2022)

Hast Du meine Version nicht versucht? Einfach und hat auf meiner Testseite perfekt funktioniert.


----------



## Max-Berater (22. Februar 2022)

Doch hab ich versucht aber irgendwo hab ich nen Fehler drinnen. Versuche es aber weiter. Gerade bin ich über 

CREATE TABLE AS SELECT​Befehl gestolpert. Evtl. ein Ansatz?


----------



## Yaslaw (22. Februar 2022)

Mach das nicht. WIrd nur komplizierter.
Kannst du der Tabelle nicht eine ID mit einem Auto-Wert hinzufügen? Es würde alles stark vereinfachen

```
ALTER TABLE `t_2124206`
    ADD COLUMN `ID` INT NOT NULL AUTO_INCREMENT,
    ADD INDEX `IDX_1` (`ID`);
```
Dann kannst du ein einfaches Update mit 2 Quellen durchführen. Achtung, Spaltennamen und Tabellenname sind von meinerm Test

```
UPDATE
    t_2124206 t1,
    (
        SELECT
            ID,
            IFNULL(
                CASE WHEN TRIM(BELEGFELD_1)=''
                THEN NULL
                ELSE BELEGFELD_1 END,
                LAG(BELEGFELD_1, 1) over (PARTITION BY BELEGFELD_2 ORDER BY BELEGFELD_1 DESC)
            ) AS blg
        FROM
            t_2124206
    ) t2
SET t1.BELEGFELD_1 = t2.blg
WHERE t1.ID = t2.ID
;
```


----------



## Max-Berater (22. Februar 2022)

Ich habe es hoffentlich so lösen können.

CREATE TABLE DATEV_table
  AS (  SELECT IFNULL(CASE WHEN TRIM(t.`Belegfeld 1`)='' THEN NULL ELSE t.`Belegfeld 1` END,
        LAG(t.`Belegfeld 1`, 1) 
            over (
                -- Gruppieren über BELEGFELD_2
                PARTITION BY t.`Beleginfo - Inhalt 4`  
                -- Absteigend sortiert BELEGFELD_1
                ORDER BY t.`Belegfeld 1` DESC
            )
    ) AS NEU_BELEGFELD_1,
    t.*


FROM DATEV t);


----------



## Max-Berater (22. Februar 2022)

Ich werde es nun morgen versuchen weiter zu verfeinern, so dass das Ergebnis so ist, wie ich es mir vorgestellt habe und berichten.

Vorab herzlichen Dank an die Community, dass Ihr mich so gut Unterstützt bei Fragen. Nochmals DANKE


----------



## Max-Berater (23. Februar 2022)

Hallo, werde ich auch mal testen gleich. Bin froh dass ich einen Ansatz gefunden habe, wie es gehen könnte.


----------



## Zvoni (23. Februar 2022)

Max-Berater hat gesagt.:


> Hallo, werde ich auch mal testen gleich. Bin froh dass ich einen Ansatz gefunden habe, wie es gehen könnte.


So wie es Yaslaw in Post #45 beschrieben hat.
Du brauchst eine eindeutige Identifikations-Spalte.


----------

