Information ausblenden
Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm

Insert in mehrere Schritten teilen

Dieses Thema im Forum "Microsoft SQL Server" wurde erstellt von norwegen60, 23 Dezember 2015.

  1. norwegen60

    norwegen60 Benutzer

    Hallo zusammen,

    ich habe eine Tabelle, in der viele Messwerte in einem Memo abgespeichert wurde. Diese Memodaten möchte ich per folgendem SQL in eine "saubere" Tabelle aufsplitten, in der jeder Messwert in einem eigenen Feld liegt
    Code:
     insert into zzRunProtocol (RelDataSet, [Type], ValueGes, TimePoint, Value)
    select RelDataSet, [Type], SUBSTRING(Memo1, Number+1, 30) as [Value],
    SUBSTRING(Memo1, Number+1, CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))-1),
    SUBSTRING(Memo1, Number+CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))+1, CHARINDEX(';', SUBSTRING(Memo1, Number+1, 30)) - CHARINDEX(',', SUBSTRING(Memo, Number+1, 30))-2)
    from MemoStore
     join zzNumbers on (number <= LEN(Memo1)) and (SUBSTRING(Memo1, Number, 1) = ';') and (len(SUBSTRING(Memo1, Number+1, 30))>3)             
     
    Problem ist, das die Tabelle mehrere tausend Sätze enthalten kann und in dem Memo noch mal mehrere tausend Einzelwerte liegen können. Das würde bedeuten, dass mit dem Insert auf einmal mehrere Mio. Datensätze eingefügt würden.

    Mit folgendem Ansatz könnte ich das jetzt in kleinere Schritte aufsplitten.
    Code:
    BEGIN TRANSACTION	                
    -- Messwerte aus der bestehenden Tabelle MemoStore auslesen, in Einzelwerte extrahieren und in zzRunProtocol speichern 
    insert into zzRunProtocol (RelDataSet, [Type], ValueGes, TimePoint, Value)
    select RelDataSet, [Type], SUBSTRING(Memo1, Number+1, 30) as [Value], 
    SUBSTRING(Memo1, Number+1, CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))-1),
    SUBSTRING(Memo1, Number+CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))+1, CHARINDEX(';', SUBSTRING(Memo1, Number+1, 30)) - CHARINDEX(',', SUBSTRING(Memo, Number+1, 30))-2)
    from MemoStore
    join zzNumbers on (number <= LEN(Memo1)) and (SUBSTRING(Memo1, Number, 1) = ';') and (len(SUBSTRING(Memo1, Number+1, 30))>3)              
    where RelDataSet between 1 and 300
    COMMIT
    
    BEGIN TRANSACTION	                
    -- Messwerte aus der bestehenden Tabelle MemoStore auslesen, in Einzelwerte extrahieren und in zzRunProtocol speichern 
    insert into zzRunProtocol (RelDataSet, [Type], ValueGes, TimePoint, Value)
    select RelDataSet, [Type], SUBSTRING(Memo1, Number+1, 30) as [Value], 
    SUBSTRING(Memo1, Number+1, CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))-1),
    SUBSTRING(Memo1, Number+CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))+1, CHARINDEX(';', SUBSTRING(Memo1, Number+1, 30)) - CHARINDEX(',', SUBSTRING(Memo, Number+1, 30))-2)
    from MemoStore
    join zzNumbers on (number <= LEN(Memo1)) and (SUBSTRING(Memo1, Number, 1) = ';') and (len(SUBSTRING(Memo1, Number+1, 30))>3)              
    where RelDataSet between 301 and 600
    COMMIT
    ... 
    Wie aber kann ich das so automatisieren, dass ich nicht bis zur höchsten RelDataSet Einzelschritte programmieren muss. Am liebsten wäre mir, dass ich zuerst über (RelDataSet max /Schrittweite) die Anzahl der SQL-Schritte festlege und die dann über eine Schleife automatisch durchlaufe.

    Oder hat jemand noch einen besseren Ansatz?

    Vielen Dank
    Gerd
     
  2. ukulele

    ukulele Datenbank-Guru

    Also eine Schleife macht ja im Gegensatz zu einem einzigen Insert nicht unbedingt mehr Sinn, du kannst die Schleife nicht pausieren oder unterbrechen. In beiden Fällen würde die Aufgabe in einem Stück erledigt werden, die Schleife könnte höchstens zwischendurch Meldungen über den Fortschritt zurück geben.

    Ich würde dem Quelldatensatz ein weiteres Atribut "verarbeitet" zuordnen. Dann würde ich ein Statement schreiben, das die ersten 10, 100 oder egal wie viele Datensätze nimmt und durchläuft (das kann ein einziger Select oder eine Schleife sein) und dann "verarbeitet" auf 1 setzt. Wenn das Script bereits verarbeitete Datensätze ignoriert kannst du es immer wieder ausführen bis alles fertig ist.
     
  3. norwegen60

    norwegen60 Benutzer

    Daran habe ich auch schon gedacht. Problem ist, dass ich die Quelldaten wenn möglich nicht anfassen soll. Aber selbst wenn, wie mache ich es dann, dass die Daten erst gekennzeichnet werden, wenn sie auch wirklich verarbeitet sind und wie bau ich die Schleife auf, dass sie sich so lange wiederholt, bis alles abgearbeitet ist. Zumal wenn du sagst, dass die Daten auch in einer Schleife in einem Stück abgearbeitet würden.

    Das versteh ich aber auch nicht ganz. Mit meinen "manuellen" Schritten hat der Übertrag funktioniert, während es beim Abarbeiten in einem Stück zu einem Timeout oder Speicherüberlauf kam. Blöderweise muss ich ein Tool verwenden, dass mir keine Rückmeldung gibt, weshalb die "in einem Stück-Lösung" abbricht. Ich habe nur nach einigem Rumprobieren herausbekommen, dass die Filterlösung geht, die am Stück-Lösung nicht.
     
  4. Walter

    Walter Administrator Mitarbeiter

    Das machst Du in einer Transaktion - die stellt die Integrität der Daten sicher.
     
    akretschmer gefällt das.
  5. norwegen60

    norwegen60 Benutzer

    Mich hat der Kommentar
    etwas verunsichert. Denn ich war auch der Meinung, dass eine Transaktion erst vollständig abgearbeitet wird bevor die nächste startet.

    Ich habe es jetzt so gelöst
    Code:
    declare @iStep int
    declare @iLoop int
    set @iStep = 100
    set @iLoop = 0
    
    while @iLoop * @iStep < (select MAX(RelDataSet) from MemoStore)
    BEGIN
      BEGIN TRANSACTION
          insert into zzRunProtocol (RelDataSet, Type, ValueGes, TimePoint, Value)
          select RelDataSet, Type, SUBSTRING(Memo1, Number+1, 30) as [Value],
            SUBSTRING(Memo1, Number+1, CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))-1),
            SUBSTRING(Memo1, Number+CHARINDEX(',', SUBSTRING(Memo1, Number+1, 30))+1, CHARINDEX(';', SUBSTRING(Memo1, Number+1, 30)) - CHARINDEX(',', SUBSTRING(Memo, Number+1, 30))-2)
          from MemoStore
          join zzNumbers on (number <= LEN(Memo1)) and (SUBSTRING(Memo1, Number, 1) = ';') and (len(SUBSTRING(Memo1, Number+1, 30))>3)
          where RelDataSet between ((@iLoop * @iStep) + 1) and ((@iLoop + 1) * @iStep)
      COMMIT
      set @iLoop = @iLoop + 1
    END   
    
    d.h. über iStep kann ich festlegen, wie viele Datensätze in einer Transaktion abgearbeitet werden und über iLoop durchlaufe ich die Schleife so oft, bis auch der Datensatz mit der höchsten ID (in dem Fall RelDataSet) abgearbeitet ist
     
  6. ukulele

    ukulele Datenbank-Guru

    Die Information könnte auch in einer eigenen Tabelle stehen die mit IDs der Datensätze gefüllt wird, die verarbeitet wurden.
    Alles was in einer Transaktion geschieht, wird kann mit einem ROLLBACK rückabgewickelt werden. Mir scheint das hast du in meiner Abwesenheit schon gelesen :)
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden