SQL Server 2008 VARCHAR(50) から Uniqueidentifier への変換
-
22-08-2019 - |
質問
varchar(50) 列を uniqueidentifier に変換しようとしていますが、このエラーが常に表示され続け、理由がわかりません。
"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."
列内のデータは現在有効な uniqueidentifier です。
私がやりたいことを実現する適切な方法は何ですか?
ありがとう
解決
あなたは、空の文字列を含むすべての列を持っていますか?即ちNOT NULLと、文字列の長さ= 0ます。
それとも、非標準文字を任意のGUIDを持っていますか?即ちない0-9、A-F?
私たちは、私はそれを継承する前に作成された私のアプリケーションでいくつかの非標準のGUIDを持っている...
EDITます:
将来のヘルプについては、このスクリプトは有効でない任意の行を見つけることができます:
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')
無効なGUIDを持っている任意の行が表示されます、とで見つけることができます:
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'
他のヒント
これはすでに回答済みであることは承知していますが、もう少しエレガントなアプローチがあります。単純化したものを使用できます。 正確に 1 文字のワイルドカード 構文 (つまり、 []
) で許可されます LIKE
有効な 16 進数をテストする句 (つまり、0 ~ 9 および A ~ F)。そして、を使用することで、 LIKE
句を単一文字検索で使用すると、有効な GUID / の形式を強制することもできます。 UNIQUEIDENTIFIER
より読みやすい方法で REPLACE
このメソッドでは、有効な形式と比較する前に、まずすべての 16 進数を 0 に正規化する必要があります。
設定
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);
テスト
以下の例では、32 セットの使用を示しています。 [0-9A-F]
GUID の 16 桁の位置ごとにダッシュ (-
) を適切な場所に配置します。ご注意ください:
- バックスラッシュ (
\
) の各行の末尾LIKE
パターンは T-SQL 行継続文字, 、 そして - バイナリ照合を使用して、「0 ~ 9」および「A ~ F」の範囲が、その範囲内の値を持つが特に 10 進数ではない文字と一致しないことを確認する必要があります。たとえば、上付き文字「2」(
²
) は 10 進数の 2 ではありませんが、範囲ワイルドカードで使用すると値 2 になります。 そして Unicode 比較規則を使用します (これは、すべての項目に使用される規則です)。NVARCHAR
データ そして 平VARCHAR
もし 照合順序は Windows 照合順序です -- 照合順序名 ない で始まりますSQL_
)。テスト行 #9 はこのケースを検証します。ただし、バイナリ比較を行うには、範囲パターンを作成する必要があります。[0-9A-Fa-f]
または列をUPPER()
関数。使用Latin1_General_100_BIN2
SQL Server 2000 または 2005 を使用している場合を除き、SQL Server 2000 または 2005 を使用する場合は、Latin1_General_BIN
.
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;
また、この質問は SQL Server 2008 のコンテキストで行われたものですが、SQL Server 2012 以降を使用している人にとっては、 TRY_CONVERT 関数を使用すると、これがさらに簡単になります。
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
*/
私は非進、有効な文字を含むものを持っています。
5000行のうち、