Achtung – Urheberrechtshinweis!
Die Artikel dieses Blogs stehen unter einer CREATIVE COMMONS LICENSE! Bitte beachten Sie die entsprechenden Hinweise auf http://creativecommons.org/licenses/by-sa/2.0/de/
Bei Fragen oder Anregungen wenden Sie sich bitte an blog {at} fourdragons(.)de
Heute möchte ich einmal ein kleines Script bzw. eine kleine Funktion vorstellen die zum Zerlegen von Strings sehr nützlich sein kann.
Wenn man strukturierte Texte vorliegen hat und daraus bestimmte Teile extrahieren soll, so kann man dies sicher mit den Stringfunktionen von T-SQL erledigen. Gerade die Verarbeitung von Listen (Kommasepariert oder sonst irgendwie) bedingt aber die wiederholte Extraktion von Textblöcken (Token) die durch verschiedenste Begrenzungszeichen voneinander getrennt sind.
Als Token verstehe ich in diesem Zusammenhang Teile eines Textes die durch Begrenzer (Delimiter) voneinander logisch getrennt werden. In einem Satz wären das die Worte, in einer Liste die durch z.B. Komma getrennten Artikelnummern oder einfach Bestandteile eines Tabellennamens usw.
Sehen wir uns hierzu mal ein paar Beispiele an:
- String: ‘Hello World, how are you?’
- String: ‘123,2345,231234,3456′
- String: ‘[AdventureWorks].[Person]. [Contact]‘
Extrahieren wir mal das dritte Wort aus Beispiel 1, den zweiten Parameterwert aus Beispiel 2 und den Tabellennamen aus Beispiel 3!
Mit Standardmitteln sicherlich ebenfalls zu realisieren, jedoch mit einer Funktion viel eleganter und Übersichtlicher zu gestalten:
Mehr…
Achtung – Urheberrechtshinweis!
Die Artikel dieses Blogs stehen unter einer CREATIVE COMMONS LICENSE! Bitte beachten Sie die entsprechenden Hinweise auf http://creativecommons.org/licenses/by-sa/2.0/de/
Bei Fragen oder Anregungen wenden Sie sich bitte an blog {at} fourdragons(.)de
Wenn man in einem Ausdruck einen CASE-Block verwendet, so ist dies auf den ersten Blick noch keine Besonderheit. Vergisst man jedoch dabei, dass SQL Server eine implizite Datentypkonvertierung vornimmt, so kann dies zu fehlerhaften Ergebnissen führen die noch dazu sehr schwer zu finden sind.
Betrachten wir hierfür einmal folgendes Beispiel:
| 01 | DECLARE @AlteKndNr VARCHAR(15) |
| 02 | DECLARE @Von VARCHAR(15) |
| 03 | DECLARE @Auf VARCHAR(15) |
| 04 | DECLARE @Regel INT |
| 05 | |
| 06 | SET @AlteKndNr = 'K011110999-VIP' |
| 07 | |
| 08 | SET @Regel = 1 |
| 09 | SET @Von = CASE @Regel WHEN 1 THEN '099' WHEN 2 THEN '0111' ELSE 0 END |
| 10 | SET @Auf = CASE @Regel WHEN 1 THEN '033' WHEN 2 THEN '0000' ELSE 0 END |
| 11 | |
| 12 | SELECT NeueKndNr = REPLACE(@AlteKndNr, @Von, @Auf), @Von, @Auf |
| 13 | |
| 14 | SET @Regel = 2 |
| 15 | SET @Von = CASE @Regel WHEN 1 THEN '099' WHEN 2 THEN '0111' ELSE 0 END |
| 16 | SET @Auf = CASE @Regel WHEN 1 THEN '033' WHEN 2 THEN '0000' ELSE 0 END |
| 17 | |
| 18 | SELECT NeueKndNr = REPLACE(@AlteKndNr, @Von, @Auf), @Von, @Auf |
| 19 | |
| 20 | -- ------------------------------------------------------------------------- |
| 21 | -- Ergebnisse: |
| 22 | -- |
| 23 | -- NeueKdNr bei @Regel = 1: K011110339-VIP = OK |
| 24 | -- NeueKdNr bei @Regel = 2: K0010999-VIP = FALSCH |
| 25 | -- K000010999-VIP = Das währe richtig! |
| 26 | -- ------------------------------------------------------------------------- |
| 27 | |
Mehr…
Achtung – Urheberrechtshinweis!
Die Artikel dieses Blogs stehen unter einer CREATIVE COMMONS LICENSE! Bitte beachten Sie die entsprechenden Hinweise auf http://creativecommons.org/licenses/by-sa/2.0/de/
Bei Fragen oder Anregungen wenden Sie sich bitte an blog {at} fourdragons(.)de
In T-SQL sind per Definition keine Arrays vorgesehen. Es gibt jedoch Fälle in denen der Einsatz eines Arrays von Vorteil wäre.
In einem konkreten Fall soll eine Prozedur einen Datenwert als Parameter erhalten. Dieser Wert wird jedoch in den, für die Abfrage zugrundeliegenden Tabellen nicht direkt verwendet. Vielmehr wird auf den Parameterwert nur indirekt über den Primärschlüssel (IdentityFeld) der Schlüsseltabelle verwiesen.
In der Prozedur müsste jetzt eine Abfrage in der Form:
| 1 | SELECT <feldliste> |
| 2 | FROM <komplexe Abfrage> |
| 3 | join Schlüsseltabelle ON Code = |
| 4 | <parameterwert></parameterwert></komplexe></feldliste> |
erstellt werden.
Grundsätzlich ist dagegen ja nichts einzuwenden. Wenn der Join gegen die Schlüsseltabelle jedoch die Laufzeit des Gesamtstatements spürbar verlängert und zusätzlich in der Prozedur dieser Join mehrfach verwendet wird, dann sollte man darüber nachdenken ob es vielleicht eine performantere Lösung gibt.
Da es kein Array in T-SQL gibt kann man dieses als String simulieren. Dieses virtuelle Array trennt die einzelnen Werte durch einen definierten Delimiter (in meinem Fall ‘|’ der senkrechte Strich). Bei der Abfrage muss jetzt nur der Abfragewert in einen String mit umgebenden Delimitern convertiert werden und über CHARINDEX mit der virtuellen Array-Variablen verglichen werden.
Eine Lösung könnte damit in etwa so aussehen:
| 1 | <erstelle ARRAY mit IdentWerten die durch parameterwert definiert sind> |
| 2 | SELECT <feldliste> |
| 3 | FROM <komplexe Abfrage> |
| 4 | WHERE CHARINDEX('|'+CONVERT(VARCHAR(10),<quellfeld>)+'|',@ARRAY) > 0</quellfeld></komplexe></feldliste></erstelle> |
Mehr…
Achtung – Urheberrechtshinweis!
Die Artikel dieses Blogs stehen unter einer CREATIVE COMMONS LICENSE! Bitte beachten Sie die entsprechenden Hinweise auf http://creativecommons.org/licenses/by-sa/2.0/de/
Bei Fragen oder Anregungen wenden Sie sich bitte an blog {at} fourdragons(.)de
Gerade wenn man ein bestehendes Datenbanksystem optimieren möchte, könnte die Frage nach der durchschnittlichen Breite einer Abfrage auftauchen. Speziell wenn man keine Tabelle zur Hand hat die in ihren Properties zumindest den verbrauchten Speicherplatz anzeigt, ist die nachfolgende Prozedur vielleicht ganz nützlich.
Es werden für eine gegebene Abfrage die Ergebnisse in eine temporäre Tabelle geschrieben und dann mittels der Funktion DATALENGTH die tatsächliche Länge eines Feldes bestimmt. Die durchschnittliche Summe der Gesamtlänge eines Datensatzes wird in der Rückgabe angezeigt.
Wenn man diese Durchschnittslänge mit der Anzahl der Datensätze multipliziert, erhält man den Nettowert des Datenvolumens das transferiert wird. (zumindest annähernd;))
Wenn ein Feld einen NULL-Wert enthält, setzt die Prozedur eine Feldlänge von 4 Byte ein. Dies wird als Mittelwert einer leeren Feldlänge verwendet und könnte in einer weiteren Ausbaustufe ggf. noch aus den System-Views für die Feldtypen genauer bestimmt werden.
Die Abfrage sollte eine repräsentative Menge an Daten zurückliefern. Es ist vor allem bei sehr großen Ergebnismengen ein wenig Vorsicht angesagt, um nicht die Temp-Datenbank in Bedrängnis geraten zu lassen
Mehr…