T-SQL Cursor – Update von Zellen mittels Variablen Inhalten

Hilmar82

Benutzer
Beiträge
6
Hallo Zusammen,
ich habe folgendes Problem.
In einer SQL Tabelle sind zwei Spalten enthalten. Dabei enthält die erste Spalte die ID, als PK, und die zwei Spalte einen Server-Hostnamen.
Allerdings ist die zweite Spalte nicht durchgehend gefüllt und ich möchte die Lücken auffüllen, und zwar immer mit den vorher gültigen Server-Hostnamen.

Bsp:
ID | Hostname (Spaltenname)
1 | Server1
2 |
3 |
4 | Server2
5 |
6 | Server3
7 |
8 |
9 |

7035 |

D.h. der Server1 soll für die IDs 2,3 verwendet werden.

Wenn Hostname gefüllt ist, soll der neue Wert, in diesem Fall Server2 für die ID5 hinterlegt werden.
Für die ID 7,8,9 wäre es der Server3 und so weiter.

Mein Gedanke war ein Cursor zu programmieren, um die Werte aufzufüllen.
D.h. prüfen ob ein Wert vorhanden ist; wenn ja, Variabel füllen. (Variabel <= Server1)
Wenn der Wert für Hostname NULL ist, Inhalt der Variabel einsetzen.
Wenn der Wert für Hostname (NOT Hostname is NULL) ist, die Variabel aktualisieren und ab dem Zeitpunkt die Werte für Hostname mit der neuen Variabel befüllen.
Insgesamt habe ich in der Tabelle 7.035 Zeilen.
Die ID ist fortlaufend.
Somit bildet die ID den Rahmen für den Cursor.
Zur Erklärung, warum ich dieses brauche.
In der Tabelle ist noch eine dritte Spalte. In der stehen die Installierten Software Produkte. Und benötige für ein Import-Verfahren, zu jedem Softwareeintrag den gültigen Server-Name.
Leider ist der einzige Cursor, welcher funktioniert, der in meinem Kopf und der befindet sich aktuell in einer Endlos-Schleife ohne einen Output zu liefern.
Vielleicht kennt Jemand von Euch eine Lösung für mein Problem.
D.h. wie müsste der Cursor programmiert werden, damit die Hostnamen-Spalte vollständig ist.
Vielen Dank im Voraus für die Unterstützung.
 
Werbung:
In einer Cursor Loop "order by ID" brauchst Du eine Variable, die sich den not null Wert merkt und bei Null als Quelle für ein Update dient.
Voraussetzung ist ein Sortierkriterium wie eben die ID.

Es geht auch ohne Cursor, z.B.:
Code:
 UPDATE data 
    SET hostname =(     
                     SELECT MAX(T2.hostname)
                       FROM data T2
                      WHERE T2.hostname IS NOT NULL
                        AND T2.id <= data.id
                  )   
  WHERE hostname IS NULL
 
Cursor sollte man vermeiden wenn es geht, in diesem Fall viel zu kompliziert gedacht. Es ginge vermutlich auch noch mit UPDATE JOIN und lead() / lag() aber da es sich vermutlich nicht um einen regelmäßigen Vorgang handelt muss man da jetzt nicht in Schönheit sterben, das UPDATE von dabadepdu tut seinen Job.
 
Vielen Dank für die Zusendung des Update-Statements.
Ich habe das Statement in meine SQL-Prozedur integriert - Schönheit ist relativ, Hauptsache es funktioniert 😉
Nach dem Update der SQL-Tabelle habe ich die Daten geprüft und festgestellt, dass das Update nicht durchgehend funktioniert hat.
D.h. teilweise wurden die Daten wie erwartet aktualisiert und teilweise wurde der zuvor genutzte Name übernommen.
Ich habe die Daten nochmals separiert und den Test mittels der IP-Adresse ausgeführt.
Gleiches Ergebnis.
Heißt das Verfahren ist leider nicht stabil.
Basierend auf dem zugesandten Code habe ich folgende Anpassungen vorgenommen:

UPDATE [dbo].[t__020_004b__Windows_Mapping_IPAddress]
SET IPAddressNew =(
SELECT MAX(T2.IPAddressNew)
FROM [dbo].[t__020_004b__Windows_Mapping_IPAddress] T2
WHERE NOT T2.IPAddressNew IS NULL
AND T2.ID <= [dbo].[t__020_004b__Windows_Mapping_IPAddress].ID
)
WHERE IPAddressNew IS NULL

=>> sollte eigentlich von der Logik identisch zum zugesandten Update-Statement sein.
=>> die IP-Adresse habe ich in eine separate Spalte dupliziert habe, um das Update überprüfen zu können.

Die Verschiebung habe ich als Abbildungen angehängt.

Abbildung.PNG

IDs, welche funktionieren:
2, 79, 232

IDs, welche nicht funktionieren:
107, 149, 190

Ich stehe vor einem Rätsel, warum das Statement nicht durchgehend das tut, was erwartet wird.
Ich habe sogar mittels BETWEEN das Update nur auf die IDs 107 – 200 ausgeführt.
Oder den Wert als String + ID hinterlegt. Siehe Abb.

Das Verhalten ist reproduzierbar.

Aber warum?

Als SQL-Server nutzen wir die Edition/Version:
Microsoft SQL Server 2019 (RTM-CU15) (KB5008996) - 15.0.4198.2 (X64) Copyright (C) 2019 Microsoft Corporation Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2019 Standard 10.0 <X64> (Build 17763: ) (Hypervisor)

Und in der SQL Tabelle sind die folgenden Datentypen hinterlegt:


CREATE TABLE [dbo].[t__020_004b__Windows_Mapping_IPAddress](
[ID] [int] NOT NULL,
[IPAddressNew] [nvarchar](50) NULL,
[IPAddress] [nvarchar](50) NULL
) ON [PRIMARY]
GO


Hat jemand eine Idee, warum das Statement nicht funktionieren könnte?
 
Ich habe die Lösung gefunden... und nochmals einen Workaround integriert.
Lag daran, dass bei dem Vergleich der Strings Server79 und Server107 die 7 größer war.
Damit wurde weiterhin der String Server79 hinterlegt.
Erst bei den größern Zahlen hatte es wieder funktioniert.
Da bei IP-Adressen und Server Hostname ähnliche Probleme auftreten, arbeite ich nun für das Update mit dem Datentyp Int. Über ein paar Zwischenspeicherungen kommt man dann auch zum Ziel... und nein Hübsch ist es nicht, aber es funktioniert :)
 
Ja, alphanumerische Sortierung von Zeichen, die Ziffern enthalten, funktioniert halt anders, als numerischer Sortierung von Zahlen.
 
Also zunächst muss man sagen SQL ist immer "stabil" und ein UPDATE tut auch immer genau das, was es soll. Entspricht das Ergebnis nicht den Erwartungen liegt i.d.R. ein Denkfehler vor, kein Bug. SQL ist enorm zuverlässig.

Vor dem Hintergrund musst du deinen Code so lange debuggen bis er liefert was du erwartest oder du erwartest, was er liefert ;-)

Wenn du den Code mehrfach nutzen willst (du schreibst von einer Prozedur) dann solltest du das sehr genau betrachten. Die Variante kann bei großen Datenmengen schnell zu Problemen führen. Jetzt könnte man wieder über einen Cursor nachdenken aber es gibt bessere alternative Vorschläge, ich habe hier einige gute gesehen:
Das mit CROSS APPLY hab ich auch anderweitig viel gesehen, die als Lösung markierte Variante mit Blog-Erklärung ist aber definitiv auch was auf das ich nie kommen würde :)
 
Ich habe die Lösung gefunden... und nochmals einen Workaround integriert.
Lag daran, dass bei dem Vergleich der Strings Server79 und Server107 die 7 größer war.
Damit wurde weiterhin der String Server79 hinterlegt.
Daher überlegt man sich bei seinem Server-Namenskonzept eine einheitliche Stelle als Zähler. Bei max 999 Servern wäre das dann Server079 und Server107.
 
Viele gute Hinweise*, aber man muss nicht unbedingt nach Zebras in Alaska suchen.

IP Adressen als Stringtyp zu sortieren, und das Maximum basiert auch auf Sortierung, kann einfach nicht gut gehen. Die Angaben aus dem Eröffnngspost haben dazu nichts hergegeben. Die Abfrage ist also stabil und zeigt mit Sicherheit reproduzierbare Ergebnisse.

Und ja, anhand der IP Adressen vielleicht nicht das, was man "erwartet", aber es wird sogar auf verschiedenen DB identische Ergebnisse produzieren.

Erst wenn man IP Typen verwendet oder die IP so formatiert, dass sie einem alphanumerischen Schema folgt, entspricht dann das Ergebnis auch manchen Erwartungen ( was ja offenbar irgendwie durch den TE schließlich gemacht wurde)

*zu "Procedure" & große Datenmenge:
Wenn das ein Standardvorgehen sein soll, würde ich anstelle des TE ernsthaft über Prozesse und Datenhaltung nachdenken wollen. Für mich sieht es einfach nach einer Datenreparatur aus. Ich hoffe, das mit der "Prozedur" ists kein Indiz für gewollte "Stabilität", also Wiederverwenbarkeit und Langzeitnutzung, oder sogar für große Datenmengen!
 
IP's sollten nicht so die Rolle spielen. Dafür gibt es Hostnamen. Aber das geht eher in die System Administration.
 
Werbung:
Man könnte die Hostnamen zerlegen in einen nicht-numerischen und einen numerischen Teil, nur für die Sortierung. Aber das ist natürlich alles andere als robust. Auch sollte keinen Daten abhängig sein von einer Sortierung die nur auf einem Namenskonzept beruhen, so ein System kann sich halt ändern. Wenn sich nur die Reihenfolge ändert ist das nicht schlimm aber wenn jetzt Informationen auf dieser Basis weiter "vererbt" werden dann muss das wasserdicht werden.

Wenn IP-Adressen sortiert werden sollen, da habe ich auch einiges gebastelt. Aber das Problem bleibt, es sollten keine Daten geschrieben werden abhängig von einer Sortierung die, durch was auch immer, durchbrochen werden kann. Der Nachfolgeserver kann ja auch schlecht immer die nächst höhere IP des Vorgängers bekommen, das muss ja knallen.

Vielleicht gibt es die Möglichkeit einen FK auf den Vorgänger als Spalte zu führen, das wäre sauber.
 
Zurück
Oben