Linuchs: DB Tabellenzeile kopieren

Moin,

bisher habe ich eine Zeile gelesen und dann ein Insert gemacht, indem alle Felder aufgezählt werden. Typische Anwendung: Ein Flohmarktbetreiber erzeugt gleichartige Events mit verschiedem Datum.

Nun sind neue Felder dazu gekommen, die sind in der Kopie nicht dabei.

Ich möchte die Quelle lesen, einige Felder leeren und dann den ganzen Schwung als neuen Datensatz schreiben.

Wie geht das? Der Suchbegriff [mysql tabellenzeile kopieren] brachte keine Hinweise.

Gruß, Linuchs

  1. Lieber Linuchs,

    bei allem schuldigen Respekt, aber diese Problembeschreibung verstehe ich wirklich nicht. Was genau willst Du da tun?

    Ich möchte die Quelle lesen, einige Felder leeren und dann den ganzen Schwung als neuen Datensatz schreiben.

    Hast Du ein konkretes Beispiel, welches Dein Problem nachvollziehbar macht?

    Wie geht das? Der Suchbegriff [mysql tabellenzeile kopieren] brachte keine Hinweise.

    Willst Du in derselben Tabelle einen Datensatz verändern („einige Felder leeren“) und dann eine Art Kopie einfügen („und dann den ganzen Schwung als neuen Datensatz schreiben“)?

    Liebe Grüße

    Felix Riesterer

    1. Lieber Felix,

      Ich möchte die Quelle lesen, einige Felder leeren und dann den ganzen Schwung als neuen Datensatz schreiben.

      Puh, ist das so unverständlich formuliert?

      Der Reihe nach:

      1. Datensatz wird wie zum Ändern angeboten, kann ein neues Datum bekommen, vielleicht beim Wanderzirkus einen anderen Ort.

      2. Statt UPDATE erfolgt nun aber ein INSERT, ein neuer Satz wird in die DB geschrieben mit allen Feldern.

      SELECT * FROM termine ...
      ...
      $row = mysql_fetch_assoc( $res );
      $row['datum'] = '';
      INSERT INTO termine ...
      # und jetzt alle Felder, ohne einzeln aufzuzählen
      

      Gruß, Linuchs

      1. Puh, ist das so unverständlich formuliert?

        Ja.

      2. Lieber Linuchs,

        Puh, ist das so unverständlich formuliert?

        nicht unverständlich, sondern missverständlich. Du schreibst von Ändern und willst in der technischen Umsetzung aber kein Update. Warum nicht? Warum willst Du stattdessen einen neuen Datensatz? Und wenn schon, was wird aus dem alten Datensatz?

        Wenn Du hier nach einer konkreten Syntax für etwas suchst, kann Dir am besten geholfen werden, wenn man versteht, was Du zu erreichen versuchst. Das kann auch bedeuten, dass man Dir aufzeigt, dass Dein grundlegender Ansatz ungünstig gewählt ist.

        Der Reihe nach:

        1. Datensatz wird wie zum Ändern angeboten, kann ein neues Datum bekommen, vielleicht beim Wanderzirkus einen anderen Ort.

        Das ist also GUI. Der Benutzer sieht ein Formular. Die Inhalte darin haben mit einem bereits existierenden Datensatz in der DB zu tun. Soweit klar.

        1. Statt UPDATE erfolgt nun aber ein INSERT, ein neuer Satz wird in die DB geschrieben mit allen Feldern.

        Und genau hier kommt das WTF. Warum genau kein UPDATE?

        INSERT INTO termine ...
        # und jetzt alle Felder, ohne einzeln aufzuzählen
        

        Was genau meinst Du mit „ohne einzeln aufzuzählen“? Da ich Dir zutraue, dass Du im Handbuch selber nachlesen kannst, wie man INSERT in seinen Varianten verwenden kann, stellt sich leider diese konkrete Nachfrage.

        Liebe Grüße

        Felix Riesterer

        1. Hallo Felix,

          Puh, ist das so unverständlich formuliert?

          nicht unverständlich, sondern missverständlich. Du schreibst von Ändern und willst in der technischen Umsetzung aber kein Update.

          stimmt, die Formulierung ist offensichtlich missglückt.

          Warum nicht? Warum willst Du stattdessen einen neuen Datensatz?

          Das Konzept nennt man kopieren. Schreibt Linuchs ja auch schon im Betreff. 😉

          Und wenn schon, was wird aus dem alten Datensatz?

          Der bleibt unverändert, so wie ich die Geschichte verstehe. Er will einen Datensatz aus der Tabelle lesen, dem Besucher in einem Formular zum Bearbeiten anbieten und dann die Änderungen als neuen Datensatz in die Tabelle eintragen.

          Warum er sich so dagegen sträubt, die Spalten namentlich aufzuzählen, verstehe ich aber nicht.

          1. Statt UPDATE erfolgt nun aber ein INSERT, ein neuer Satz wird in die DB geschrieben mit allen Feldern.

          Und genau hier kommt das WTF. Warum genau kein UPDATE?

          Weil er den Ur-Datensatz behalten und eine geänderte Kopie speichern möchte.

          Einen schönen Tag noch
           Martin

          --
          Motto der DIY-Anhänger: If it ain't broken, fix it until it is.
  2. Moin,

    Ich möchte die Quelle lesen, einige Felder leeren und dann den ganzen Schwung als neuen Datensatz schreiben.

    Du suchst vermutlich INSERT … SELECT:

    INSERT INTO tabelle (foo, bar, date, new)
      SELECT foo, NULL, NOW(), 'newvalue' FROM tabelle WHERE id = 1
    

    Die Spalte foo wird dabei aus dem Quelldatensatz übernommen, die Spalte bar auf NULL gesetzt, date auf das aktuelle Datum und new bekommt den Werte »newvalue«.

    Gruß
    Tobias

    1. Hallo Tobias,

      in deinem Beispiel werden vier Felder geschrieben, richtig?

      Und wenn der neue Feldname foo2 in der DB dazukommt, muss ich den Programmcode ändern?

      Ausser dem kopierenden Programm gibt es andere, derentwegen ein neues Feld dazugekommen ist. Das muss das Kopierprogramm nicht wissen, aber mitkopieren.

      Es muss doch möglich sein, wenn ein $row die Felder alle in der Reihenfolge der Datenbank hat, irgendwas mit * zu schreiben. Aber wie ist die Syntax genau?

      Der Datensatz hat ca. 50 Felder, davon sind 20 in einer form änderbar.

      Nun möchte ich die geänderten Werte im Arbeitsspeicher ersetzen, 30 unbekannte bleiben unberührt. Dieser Datensatz, also mit genau denselben Feldnamen in genau der Reihenfolge des vorherigen SELECT * soll ein neuer Satz werden.

      1. Es muss doch möglich sein, wenn ein $row die Felder alle in der Reihenfolge der Datenbank hat, irgendwas mit * zu schreiben. Aber wie ist die Syntax genau?

        Vermutlich ist "INSERT INTO VALUES" dein Stichwort…

      2. Moin,

        Und wenn der neue Feldname foo2 in der DB dazukommt, muss ich den Programmcode ändern?

        Analog zur Spalte new die Spalte foo2 sowie den zu verwendenden Wert ergänzen.

        Ausser dem kopierenden Programm gibt es andere, derentwegen ein neues Feld dazugekommen ist. Das muss das Kopierprogramm nicht wissen, aber mitkopieren.

        Der Code sollte wissen welche Spalten in der Tabelle stehen … Einfach alle Spalten kopieren geht nicht wenn eine auto_increment-Spalte im Spiel ist, zudem könntest du dann keine Werte direkt ändern. Du wirst die Spalten von Hand raussuchen und den Query zusammenbauen müssen (die Tabelle information_schema.COLUMNS existiert).

        Ich bin mir da aber nicht so sicher ob das überhaupt sinnvoll ist was du da vor hast: zum Kopieren eines Datensatzes würde ich den bestehenden Datensatz als Standardwerte für ein Formular verwenden (ggf. Werte die auf jeden Fall geändert werden o.ä. leer lassen) und nach dem Absenden von dem die Daten als neuen Datensatz speichern.

        Gruß
        Tobias

        1. Der Code sollte wissen welche Spalten in der Tabelle stehen … Einfach alle Spalten kopieren geht nicht wenn eine auto_increment-Spalte im Spiel ist,

          Soweit man die im Blick hat und entsprechend behandelt, kann man das durchaus so machen.

  3. Ein Flohmarktbetreiber erzeugt gleichartige Events mit verschiedem Datum.

    Dein eigentliches Problem ist nicht die Abfrage bzw. der Eintrag sondern die Normalisierung.

    Für offenbar wiederkehrende Events teile die Tabelle:

    Bisher:

    spalte spalte spalte spalte spalte
    id datum ort event sonstwas

    Danach:

    Tabelle: Termine

    spalte spalte spalte spalte
    termin_id datum event_id ort_id

    Tabelle: Events

    spalte spalte spalte
    event_id event sonstwas

    Tabelle Orte: (Wer behauptet denn, dass ein Betreiber nicht Flohmärkte an verschiedenen Orten organisieren kann?)

    spalte spalte spalte
    ort_id ort sonstwas

    Möglicherweise willst Du auch noch eine Tabelle, in welcher Du Ereignis-Typen einem Benutzer zuordnest, z.B. damit dieser „seine“ Ereignis-Typen einfach im Formular auswählen kann.

    Nun sind neue Felder dazu gekommen, die sind in der Kopie nicht dabei.

    Aus welchem Grund füllst Du die Tabelle(n)? Weil Du es dem Anwender ermöglichen willst, vermittels einer Anwendung Zeug einzutragen? Flexibilität kannst Du hier erreichen, in dem Spalten der Tabelle(n), die womöglich nicht gefüllt werden, mit passenden DEFAULT-Werten besetzt werden.

    Hier ein Beispiel aus dem Handbuch:

    CREATE TABLE t1 (
      i     INT DEFAULT -1,
      c     VARCHAR(10) DEFAULT '',
      price DOUBLE(16,2) DEFAULT 500
    );
    

    (Das geht auch nachträglich mit ALTER TABLE.)

    verfügt die Anwendung also ein

    INSERT INTO t1 ( i, c     ) 
            VALUES ( 3, "foo" )
    

    oder

    INSERT INTO `t1`
    SET 
       `i` = 3,
       `c` = "foo"
    

    ... dann steht sodann

    i c price
    3 foo 500.00

    drin.

    1. Dein eigentliches Problem ist nicht die Abfrage bzw. der Eintrag sondern die Normalisierung.

      Die Beispiele Wanderzirkus und Flohmarkt hat dich auf die Idee gebracht, dass ich feststehende Events habe, die in derselben Art mit anderem Datum und Ort vorkommen.

      Das ist die AUSNAHME, weswegen ich die Kopierfunktion nachträglich gemacht habe.

      Die REGEL sind Einzelveranstaltungen von Vereinen, überwiegend Chöre. Die machen keine Tourneen mit demselben Programm, haben von Termin zu Termin andere Beschreibungen, die Bestandteil des Terminsatzes sind.

      Bei Flohmärkten und Circen / Circussen / Zierkürbissen (Plural von Circus?) gibt's dann dieselbe Beschreibung in 20 Sätzen, was solls ...

      Natürlich sind Daten in eigenen Tabellen, auf die der Terminsatz verweist:

      • adress_id
      • ort_id
      • treffpunkt_id
      • youtube_id

      Ich frage nach einer Syntax und du gehst nicht drauf ein.

      1. Die REGEL sind Einzelveranstaltungen von Vereinen, überwiegend Chöre. Die machen keine Tourneen mit demselben Programm, haben von Termin zu Termin andere Beschreibungen, die Bestandteil des Terminsatzes sind.

        Nur macht ein PROGRAMM halt immer das selbe. Das heisst, Du brauchst eine allgemeingültige Datenhaltung und Programmierung und musst Dich dabei am kompliziertesten Sachverhalt orientieren. Dabei kann es dazu kommen, dass das, was Du als Normalfall erwartest, eben aus Programmsicht der Fall ist, in welchen etwas mehr getan werden muss als in den von Dir als Sonderfall betrachteten…

        Ich frage nach einer Syntax und du gehst nicht drauf ein.

        Hab ich. Einmal mit DEFAULT und dann, im Nachtrag mit dem SUBSELECT.

        Diese beiden Lösungswege sind vorliegend auch zielführend. Womöglich brauchst Du alle 3 (DEFAUT, SUBSELECT und korrekte Normalisierung) in angemessener Kombination.

      2. Lieber Linuchs,

        Das ist die AUSNAHME, weswegen ich die Kopierfunktion nachträglich gemacht habe.

        klingt nach einem Designfehler beim Modellieren der DB.

        Bei Flohmärkten und Circen / Circussen / Zierkürbissen (Plural von Circus?) gibt's dann dieselbe Beschreibung in 20 Sätzen, was solls ...

        Ja, klingt nach einem Designfehler beim Modellieren der DB.

        Liebe Grüße

        Felix Riesterer

    2. Gibt es freilich DEFAULT-Werte, die vom User (hier: Betreiber) abhängig sind, dann kommst Du kaum umhin, eine Tabelle mit USER-Defaults zu bauen und diese beim Eintrag z.B. via Subselect nach den Werten befragen:

      INSERT INTO `t1` (
          `i`,
          `c`,
          `price`
      ) SELECT
          3,
          "foo",
          `price` FROM `user_defaults` WHERE `user_id` = 815;
      
  4. Wir diskutieren, aber es scheint keine Lösung für meine Freage zu geben.

    Ich suche sowas:

    $ow = [datum] [ort_id] [beschreibung] [veranstalter]

    INSERT INTO termine ($row)

    Und wenn später das Feld [treffpunkt] dazu kommt, soll die Kopierroutine unverändert

    INSERT INTO termine ($row)

    heißen. Geht nicht? Dann müssen wir nicht weiter diskutieren, die umständliche Methode kenne ich.

    Irgendwo war das Stichwort COLUMNS. Kenne ich, nutze ich beim selektiven Ändern. Wenn ein Feld leer aus der Form kommt, wird Default in den Datensatz gesetzt.

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Spalten-Namen (keys)
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    SHOW FULL COLUMNS FROM ".$db[0]['termine'];
      $res_cols = @mysql_query( $q, $conn_id ); zeigSqlFehler( $q, $conn_id );
    
    1. Wir diskutieren, aber es scheint keine Lösung für meine Freage zu geben.

      INSERT INTO VALUES

      Immer noch.

      1. Wir diskutieren, aber es scheint keine Lösung für meine Freage zu geben.

        INSERT INTO VALUES

        Immer noch.

        Du meinst hoffentlich nicht sowas:

        INSERT INTO table_name
        VALUES (value1, value2, value3, ...);
        

        BEWARE!

        Das ist, gerade AUCH im vorliegenden Fall, so ziemlich die schlechteste Idee, die man haben kann. Denn hier herrscht weitgehend Unklarheit, was passiert und bei Programmänderungen geht der Programmierer Tabellenspalten zählen.

        1. Denn hier herrscht weitgehend Unklarheit, was passiert und bei Programmänderungen geht der Programmierer Tabellenspalten zählen.

          Gehen wir davon aus, dass ein Teil der Daten aus der form kommen.

          Was spricht dagegen, den Datensatz neu zu lesen, die (bekannten) Werte aus der form einzufüllen und 0.01 s später als INSERT zu schreiben mitsamt den unbekannten Feldern?

          1. Was spricht dagegen,

            Nun, wenn ich im Trinkwasserschutzgebiet meines Wasserwerks pinkle, dann habe ich mein Problem auch zunächst erst einmal gelöst… Was spricht also dagegen?

        2. Du meinst hoffentlich nicht sowas:

          INSERT INTO table_name
          VALUES (value1, value2, value3, ...);
          

          Doch, genau das.

          BEWARE!

          Das ist, gerade AUCH im vorliegenden Fall, so ziemlich die schlechteste Idee, die man haben kann. Denn hier herrscht weitgehend Unklarheit, was passiert und bei Programmänderungen geht der Programmierer Tabellenspalten zählen.

          Vielleicht habe ich ja nicht ausgiebig genug den Fred gelesen. Wenn ich aber davon ausgehe, dass die ganze Nummer zur Laufzeit passiert…

          Dann halte ich den Fall, dass die DB-Struktur sich zwischenzeitlich geändert hat, für... naja... vernachlässigbar.

          Soweit der https://forum.selfhtml.org/self/2022/sep/15/db-tabellenzeile-kopieren/1802116#m1802116 richtig liegt und die Spaltenreihenfolge sich ändern könnte. OK. Auch das scheint mir ZUR LAUFZEIT eher exotisch, lässt sich aber abfangen…

      2. Ach sooo ...

        KLar habe ich danach gesucht und fand sowas

        Mit deinem Link kam auf die Seite mit diesem

        Ja, das ist es wohl. Vielen Dank.

        Soweit ich weiß, kann man auch Zahlen in Hochkommas setzen und sie werden in numerische Felder richtig eingefüllt? Oder muss ich jedes Feld auf den Typ prüfen?

        Na, ich kanns ja ausprobieren.

        1. Mit deinem Link kam auf die Seite mit diesem

          Ja, das ist es wohl. Vielen Dank.

          Du wirst mir später mal glauben, dass das NICHT das ist, was Du willst. Das funktioniert nur für einen Moment, weil nur unter ganz bestimmten Bedingungen... Einen Augenblick lang (so lange diese Bedingungen erfüllt zu sein scheinen) wirst Du mir also nicht glauben…

        2. Hi,

          Mit deinem Link kam auf die Seite mit diesem

          Viel Spaß, wenn dann mal irgendwann die DB ein reorganize erfährt. Spaltenreihenfolge ist nicht garantiert ...

          cu,
          Andreas a/k/a MudGuard

          1. Viel Spaß, wenn dann mal irgendwann die DB ein reorganize erfährt. Spaltenreihenfolge ist nicht garantiert ...

            Auch wenn mir persönlich der Fall noch nicht untergekommen ist: man kann bei INSERT INTO VALUES auch Spaltennamen angeben…

            1. Lieber Mitleser,

              Auch wenn mir persönlich der Fall noch nicht untergekommen ist: man kann bei INSERT INTO VALUES auch Spaltennamen angeben…

              um gegen mögliche Änderungen am Tabellenlayout abzusichern, verwende ich grundsätzlich eine Liste der Spaltennamen, in die ich schreiben möchte:

              INSERT INTO `my_table`
               (`spalte_a`, `spalte_x`, `spalte_z`, `noch_irgend_ne_spalte`)
              VALUES
                -- 1. zu schreibender datensatz --
               ("wert_a", "wert_x", "wert_z", "noch_irgend_nen_wert"),
                -- 2. zu schreibender datensatz --
               ("wert_a", "wert_x", "wert_z", "noch_irgend_nen_wert"),
                -- 3. zu schreibender datensatz --
               ("wert_a", "wert_x", "wert_z", "noch_irgend_nen_wert")
              ;
              

              Damit kann die Reihenfolge der Spalten in der Tabelle sein, wie sie will; mit der Query kommen die Daten immer in die richtigen Spalten. Und sollten später einmal weitere Spalten hinzu kommen, dann wirft diese Query deswegen keine Fehler. Die nicht aufgeführten neuen Spalten werden dann mit Default-Werten befüllt.

              Ich habe noch immer nicht verstanden, was Linuchs eigentlich erreichen möchte.

              Liebe Grüße

              Felix Riesterer

              1. Damit kann die Reihenfolge der Spalten in der Tabelle sein, wie sie will; mit der Query kommen die Daten immer in die richtigen Spalten. Und sollten später einmal weitere Spalten hinzu kommen, dann wirft diese Query deswegen keine Fehler. Die nicht aufgeführten neuen Spalten werden dann mit Default-Werten befüllt.

                Ja, schon klar. Ich finde den Fall "zur Laufzeit" allerdings weiter eher "exotisch".

                1. Lieber Mitleser,

                  Ich finde den Fall "zur Laufzeit" allerdings weiter eher "exotisch".

                  bei Hobbybastlern kann das schon sein. Du hast da was kleines gebastelt und das läuft jetzt online vor sich hin. Dann fällt Dir ein, dass Du da was anflanschen willst, änderst etwas in der DB (weil kleines Projekt braucht keine Entwicklungsumgebung, die Live-Instanz ist die Entwicklungsumgebung 😉) - und prompt knallt es.

                  Liebe Grüße

                  Felix Riesterer

                2. Ich finde den Fall "zur Laufzeit" allerdings weiter eher "exotisch".

                  Wer sagt denn, dass die Änderung an der Tabelle "zur Laufzeit" erfolgt? Im Übrigen ist NICHT davon auszugehen, dass die Tabelle zur Laufzeit des eintragenden Skriptes erzeugt wird. Ergo kann sie zwischen Erzeugung und Beginn der Laufzeit des eintragendes Skriptes verändert worden sein.

                  Das ist gerade hier der Fall: Linuchs will ja offensichtlich seine Tabelle um Spalten erweitern bzw. hat das schon getan.

                  Zitat vom verlinkten Beitrag:

                  Nun sind neue Felder dazu gekommen, die sind in der Kopie nicht dabei.

                  Mit „Felder“ meint er offenbar „Spalten“.

                  1. Wer sagt denn, dass die Änderung an der Tabelle "zur Laufzeit" erfolgt?

                    Keine Ahnung. Ich hab beim Querlesen verstanden "will zur Laufzeit Datensatz lesen", "irgendwelche Werte" manipulieren und dann als neuen Record in die Tabelle schreiben. Wenn das Szenario zutrifft, halte ich den Weg über INSERT VALUES für absolut vertretbar. Auch bei deutlich größeren Projekten als "Hobbybastler-Niveau", wie Felix schrieb.

                    Als Head of Development bei Amazon kann und wird man die Sachlage anders beurteilen.

                    Soweit ich die Anforderung nun falsch verstanden habe, sprich "es können viele Minuten/Tage/Jahrzehnte zwischen SELECT und INSERT" vergehen, ist mein Vorschlag natürlich hinfällig.

                    1. Wer sagt denn, dass die Änderung an der Tabelle "zur Laufzeit" erfolgt?

                      Keine Ahnung. Ich hab beim Querlesen verstanden "will zur Laufzeit Datensatz lesen", "irgendwelche Werte" manipulieren und dann als neuen Record in die Tabelle schreiben. Wenn das Szenario zutrifft, halte ich den Weg über INSERT VALUES für absolut vertretbar. Auch bei deutlich größeren Projekten als "Hobbybastler-Niveau", wie Felix schrieb.

                      Als Head of Development bei Amazon kann und wird man die Sachlage anders beurteilen.

                      Nö. Schon jemand, der ungern Kopfschmerzen hat oder gerne in Zetteln wühlt, auf denen er sich die (volatile!) Reihenfolge der Spalten notiert hat, wird man bei einem INSERT (wie übrigens auch beim SELECT) die Spaltennamen angeben.

                      Dem, was Martin schrieb wäre nur noch hinzufügen, dass Linuchs wohl zu seinem eigenen, späteren Schaden bei der Scheinlösung bleiben und „wurschteln“ wird, statt es gleich richtig zu machen.

                      1. Nö. Schon jemand, der ungern Kopfschmerzen hat oder gerne in Zetteln wühlt, auf denen er sich die (volatile!) Reihenfolge der Spalten notiert hat, wird man bei einem INSERT (wie übrigens auch beim SELECT) die Spaltennamen angeben.

                        Einspruch. Die Situation ist nicht mit TOCTOU oder Ähnlichem zu vergleichen. Die Fehlerwahrscheinlichkeit bei der Nummer in EINEM Prozess ist zwar da, aber vergleichsweise gering.

                        Es gibt ne Menge Sachen, die bei Updates Probleme machen können. Ne Taballenstruktur einfach so im Handumdrehen im Livebetrieb ändern gehört definitiv dazu. LOL.

                        1. Nö. Schon jemand, der ungern Kopfschmerzen hat oder gerne in Zetteln wühlt, auf denen er sich die (volatile!) Reihenfolge der Spalten notiert hat, wird man bei einem INSERT (wie übrigens auch beim SELECT) die Spaltennamen angeben.

                          Einspruch. Die Situation ist nicht mit TOCTOU oder Ähnlichem zu vergleichen.

                          Hä? Wann und wie und wo habe ich was von „TOCTOU“ oder auch nur „Ähnlichem“ geschrieben? Vorliegend ist es sogar der Autor selbst, der seine Tabellen verändert.

                  2. Ich finde den Fall "zur Laufzeit" allerdings weiter eher "exotisch".

                    Wer sagt denn, dass die Änderung an der Tabelle "zur Laufzeit" erfolgt? Im Übrigen ist NICHT davon auszugehen, dass die Tabelle zur Laufzeit des eintragenden Skriptes erzeugt wird. Ergo kann sie zwischen Erzeugung und Beginn der Laufzeit des eintragendes Skriptes verändert worden sein.

                    Halt ich für vernachlässigbar.

                    Das ist gerade hier der Fall: Linuchs will ja offensichtlich seine Tabelle um Spalten erweitern bzw. hat das schon getan.

                    Zitat vom verlinkten Beitrag:

                    Nun sind neue Felder dazu gekommen, die sind in der Kopie nicht dabei.

                    Mit „Felder“ meint er offenbar „Spalten“.

                    Nachdem ich jetzt den OP nochmal gelesen habe… dann verstehe ich auch nicht mehr, worum es eigentlich geht. LOL.

            2. Hi,

              Auch wenn mir persönlich der Fall noch nicht untergekommen ist: man kann bei INSERT INTO VALUES auch Spaltennamen angeben…

              Dann schau Dir nochmal die beiden Statements in dem Posting, auf das ich geantwortet hatte, an.

              Linuchs hat genau diese Liste der Spaltennamen "entsorgt" und das als Lösung bezeichnet.

              cu,
              Andreas a/k/a MudGuard

        3. Ja, das ist es wohl. Vielen Dank.

          Soweit ich weiß, kann man auch Zahlen in Hochkommas setzen und sie werden in numerische Felder richtig eingefüllt? Oder muss ich jedes Feld auf den Typ prüfen?

          Die Nummer ist nicht problemfrei und ich würde sie auch nicht als best practice titulieren wollen. Aber man kann das durchaus so machen.

          Die Typisierung sollte an der Stelle m.E. wurscht sein, aber Versuch macht kluch.

    2. Hallo Linuchs,

      Wir diskutieren, aber es scheint keine Lösung für meine Freage zu geben.

      So scheint es.

      Du hast zwei Optionen:

      • Du listest die Felder explizit auf, die vom INSERT zu befüllen sind, und listet dazu passend 1:1 die Werte auf

      INSERT INTO foo (bar, baz, bing, bong) VALUES (1,2,3,4)

      An Stelle von VALUES(1,2,3,4) kann auch ein SELECT stehen, der 4 Spalten liefert.

      • Du listest die Felder NICHT auf, dann musst Du für jede Spalte einen Wert liefern. In der Reihenfolge, wie die Columns in der Table definiert sind. Dies ist eine Tretmine mit angerostetem Zünder und in einem Programm nur dann vertretbar, wenn Du die Werte mit einem SELECT * auf die gleiche Tabelle lieferst. Was aber wiederum in den allermeisten Fällen sinnfrei ist.

      Deine einzufügende Datenmenge steht in einem Array? Wie wäre es denn dann, wenn Du dieses Array so aufbaust:

      $row = [
         "datum" => $datum,
         "ort_id" => $ort_id,
         "beschreibung" => $beschreibung,
         "veranstalter" => $veranstalter
      ];
      

      Für den INSERT kannst Du die Keys aus dem Array extrahieren und daraus die Spaltennamen ableiten. Im besten Fall ist das 1:1. Wenn deine internen Namen von den Column-Namen der Tabelle abweichen, brauchst Du noch eine Mapping-Tabelle, die aus den internen Keys die Column-Namen erzeugt.

      $columns = [];
      $values = [];
      foreach ($row as $col => $val) {
         $columns[] = $col;
         $values = mysqli_real_escape_string($db, $val);
      }
      $columns = implode(",", $columns);
      $values =  implode(",", $values);
      // oder
      $values =  "'" . implode("','", $values) . "'";
      

      Weiß grad nicht ob Du die Anführungsstriche selbst erzeugen musst oder ob die aus der Escape-Funktion kommen. Je nach dem brauchst Du die obere oder untere der beiden Varianten.

      Und dann kannst Du aus Spaltennamen und Werten das INSERT-Statement zusammenbauen:

      INSERT INTO foo ($columns) VALUES ($values)

      Sicherlich fehlt da noch einiges, so dass es in dein Gesamtkunstwerk hineinpasst, und man findet sicherlich auch Gelegenheiten, sich damit in den Fuß zu schießen, aber das wäre ein Ansatz für Flexibilität.

      Rolf

      --
      sumpsi - posui - obstruxi
  5. Hätte nicht gedacht, für so ein kleines Problem so eine Diskussion loszutreten.

    Ist das Kopieren eines Datensatzes sowas Exotisches, was nur ich mache?

    Die Lösung ist nun, dass ich die row_quelle einlese, im Speicher Felder auf NULL setze, die jungfräulich sein müssen (z.B. Zugriffszähler) alle Felder als neu schreibe ausgenommen die auf NULL gesetzten und die leeren. Damit bekommen die den Default-Wert aus der Datenbank.

    $row_quelle['counter']        = NULL;
    ...
        $q = "
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # form_basis: Kopie neu anlegen
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    INSERT INTO ".$db[0]['termine']."
    SET
    ";
        $q .= " owner_id = '".$owner_id."'\n";    // damit die Folgenden mit Komma beginnen koennen
        foreach( $row_quelle AS $key => $val ) {
          if ( !is_null( $val ) && strlen( $val ) > 0 ) {
            $q .= ",".$key." = '".addslashes( $val )."'\n";
          }
        }
        $q .= ";\n";
    

    Danach wird mit der neuen id die vorhandene Änderungsroutine durchlaufen, die Werte aus form eingesetzt.

    So kompliziert wie zuvor, aber unbekannte Felder werden mitkopiert.

    Danke für das zahlreiche Mitdenken.

    1. Hallo Linuchs,

      Punkt 1:

      So ähnlich hatte ich das ja auch vorgeschlagen, nur mit der Feldnamensliste in Klammern. Ich GLAUBE, dass

      INSERT INTO table (foo, bar, baz) VALUES (1, 2, 3)
      

      gleichwertig ist mit

      INSERT INTO table SET foo=1, bar=2, baz=3
      

      Punkt 2:

      Dass addslashes missbilligt ist zum Escapen von DB-Werten und dass man mysqli_real_escape_string nimmt, hat Dir sicherlich schon drölfmal jemand gesagt.

      Punkt 3:

      Die Bedingung !is_null( $val ) && strlen( $val ) > 0 kann daneben gehen, wenn deine Werte getypt sind. strlen(false) ist 0. Allerdings ist es auch nicht besser, einfach !empty($val) abzufragen, denn empty liefert für false und die Zahl 0 ein true.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Ich GLAUBE, dass

        INSERT INTO table (foo, bar, baz) VALUES (1, 2, 3)
        

        gleichwertig ist mit

        INSERT INTO table SET foo=1, bar=2, baz=3
        

        Ich WEIß es.

        Nennt sich auch „Update-Syntax“. Und die bevorzuge ich auch, wenn ich nicht mehrere Zeilen auf einmal eintragen will. Warum zeigt sich wie folgt:

        INSERT INTO table
        SET 
          foo = 1,
          bar = 2,
          baz = 3
        

        Bei dieser Notationsweise habe sogar ICH Schwierigkeiten, noch Fehler zu fabrizieren.

        1. INSERT INTO table (foo, bar, baz) VALUES (1, 2, 3)

          In der while-Schleife habe ich key und val zusammen. Warum sollte ich sie zweimal durchlaufen, um erst die keys und dann die vals zusammenzustellen?

          Ja, ich könnte auch zwei strings bilden und die dann ins SQL setzen.

          1. Hallo Linuchs,

            warum solltest Du dafür zwei Durchläufe brauchen? Bau die Values in einem zweiten String zusammen und setze sie danach ins SQL.

            Es wäre aber auch egal - zwei Durchläufe machen den Kohl auch nicht fetter.

            Die set-Variante ist einfacher, das gebe ich zu.

            Rolf

            --
            sumpsi - posui - obstruxi
      2. Moin,

        So ähnlich hatte ich das ja auch vorgeschlagen, nur mit der Feldnamensliste in Klammern. Ich GLAUBE, dass […] gleichwertig ist mit […]

        Ist es, der Unterschied ist aber dass die VALUES-Variante offizieller SQL-Syntax und die SET-Variante MySQL-only ist.

        Gruß
        Tobias