SQL Server 2008 Konvertieren von VARCHAR (50) zu Uniqueidentifier
-
22-08-2019 - |
Frage
Ich versuche, eine varchar (50) Spalte in eine Unique zu konvertieren, aber dieser Fehler hält die ganze Zeit auftauchen, und ich weiß nicht, warum:
"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."
Die Daten in der Spalte sind derzeit gültige eindeutige.
Was ist der richtige Weg zu tun, was ich will?
Danke
Lösung
Haben Sie Spalten mit leeren Zeichenfolge? D. h NOT NULL, string length = 0.
Oder haben Sie GUIDs mit Nicht-Standard-Zeichen? D. h nicht 0-9, A-F?
Wir haben einige Nicht-Standard-GUIDs in meiner Anwendung, die erstellt wurden, bevor ich es geerbt ...
EDIT:
Für zukünftige Hilfe dieses Skript können Sie alle Zeilen finden, die nicht gültig sind:
SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0'), COUNT(*)
FROM TABLE
GROUP BY REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0')
Alle Zeilen, die ungültige Guids haben werden angezeigt und können durch gefunden werden:
SELECT *, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0')
FROM TABLE
WHERE REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0') != '00000000-0000-0000-0000-0000000000'
Andere Tipps
Ich weiß, dass dies bereits beantwortet worden, aber es ist ein etwas eleganter Ansatz. Sie können die vereinfachende, genau ein Zeichen-Platzhalter Syntax (dh []
) in einer LIKE
Klausel zulässig für gültige hexadezimale Ziffern zu testen (zB 0 - 9 und A - F). Und durch eine LIKE
Klausel mit der Einzelzeichen Suche verwenden, können Sie auch das Format eines gültigen GUID / UNIQUEIDENTIFIER
in eine besser lesbare Weise erzwingen dann die REPLACE
Verfahren, das muss zuerst alle hexadezimalen Ziffern zu 0en normalisieren vor dem gültigen Format zu vergleichen .
EINRICHTUNG
SET NOCOUNT ON;
IF (OBJECT_ID('tempdb.dbo.#GUIDs') IS NOT NULL)
BEGIN
DROP TABLE #GUIDs;
END;
CREATE TABLE #GUIDs (ID INT NOT NULL, TheGUID VARCHAR(50) NULL);
INSERT INTO #GUIDs (ID, TheGUID)
SELECT tmp.ID, tmp.TheGUID
FROM (
SELECT 1, 'E1A21B62-ACC4-4ACB-B284-0F0233F19EDA' -- valid
UNION ALL
SELECT 2, '50178543-11E6-40D2-87F1-9C4676DCF542' -- valid
UNION ALL
SELECT 3, '' -- invalid: empty string
UNION ALL
SELECT 4, '4EB30267-0EB4-413A-9B05-6EDDB943C7D8' -- valid
UNION ALL
SELECT 5, '4EB30267-0EB4-413A-9Z05-6EDDB943C7D8' -- invalid: has a "Z"
UNION ALL
SELECT 6, NULL -- invalid: is NULL
UNION ALL
SELECT 7, '18EAE6C5-7256-4598-AA0A-837718145001' -- valid
UNION ALL
SELECT 8, '18eae6c5-7256-4598-aa0a-837718145001' -- valid (lowercase version of #7)
UNION ALL
SELECT 9, '18EAE6C5-7²56-4598-AA0A-837718145001' -- invalid: has superscript "2"
) tmp (ID, TheGUID);
TESTS
Das folgende Beispiel zeigt 32 Sätze von [0-9A-F]
für jede hex-digit Position des GUID verwenden und hat die Striche (-
) an den entsprechenden Stellen. Bitte beachten Sie:
- der umgekehrte Schrägstrich (
\
) am Ende jeder Zeile in dem Muster ist dieLIKE
T-SQL-Zeilenfortsetzungszeichen und - sollten Sie eine binäre Sortierung verwenden, um sicherzustellen, dass Bereiche von „0-9“ und „A-F“ alle Zeichen nicht übereinstimmen, die Werte in diesem Bereich haben, sind aber nicht speziell Dezimalstellen. Zum Beispiel ist die obere Index „2“ Zeichen (
²
) keine dezimal 2, aber es hat einen Wert von 2, wenn sie in einem Bereich Platzhalter verwendet und mit Unicode-Vergleichsregeln (die die Regeln verwendet werden für alleNVARCHAR
Daten und auchVARCHAR
IF die Sortierung ist eine Windows-Sortierung - Kollatierungsnamen nicht mitSQL_
starten). Testzeile # 9 prüft diesen Fall. Jedoch erfordert einen binären Vergleich tun entweder den Bereich Muster[0-9A-Fa-f]
machen oder die Spalte in einerUPPER()
Funktion Verpackung. Verwenden SieLatin1_General_100_BIN2
es sei denn, Sie verwenden SQL Server 2000 oder 2005, in diesem Fall sollten SieLatin1_General_BIN
verwenden.
SELECT ID, TheGUID, CONVERT(UNIQUEIDENTIFIER, TheGUID) AS [Converted]
FROM #GUIDs
WHERE UPPER(TheGUID) COLLATE Latin1_General_100_BIN2 LIKE
'[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]\
[0-9A-F]';
SELECT ID, TheGUID AS [BAD]
FROM #GUIDs
WHERE UPPER(TheGUID) COLLATE Latin1_General_100_BIN2 NOT LIKE
'[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]\
[0-9A-F]'
OR TheGUID IS NULL;
Und während diese Frage im Zusammenhang mit SQL Server 2008 gefragt wurde, für alle, die Verwendung von SQL Server 2012 oder höher, die TRY_CONVERT Funktion macht dies noch einfacher:
SELECT tmp.ID, tmp.TheGUID AS [BAD]
FROM #GUIDs tmp
WHERE TRY_CONVERT(UNIQUEIDENTIFIER, tmp.[TheGUID]) IS NULL;
/*
ID BAD
3
5 4EB30267-0EB4-413A-9Z05-6EDDB943C7D8
6 (NULL)
9 18EAE6C5-7²56-4598-AA0A-837718145001
*/
Von 5000 Zeilen hatte ich einen ein nicht hex-gültiges Zeichen enthält.