Чтобы извлечь специальные символы, сначала нужно разбить строку на строки, чтобы вы могли запросить каждый из них по отдельности, что можно сделать с помощью таблицы чисел. Если у вас его нет, их очень легко создать на лету:
WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3)
SELECT Number
FROM Numbers;
Это дает список чисел от 1 до 10000. Подробнее об этом здесь .
Затем вы можете присоединить это к своим данным с условием Number < LEN(Email)
, чтобы гарантировать, что вы получите одну строку назад для каждого символа в электронном письме, а затем используйте SUBSTRING()
, чтобы извлечь символ в позиции n
* * 1013
DECLARE @T TABLE (ID INT IDENTITY, Email NVARCHAR(255));
INSERT @T (Email)
VALUES (N'JóhnSnów@gmail.com'), (N'Khãlessi@gmail.com'), ('NedStark@gmail.com');
WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3)
SELECT t.ID,
t.Email,
Character = SUBSTRING(t.Email, n.Number, 1)
FROM @T AS t
INNER JOIN Numbers n
ON n.Number < LEN(t.Email)
ORDER BY t.ID;
Что дает:
ID Email Character
-----------------------------
1 JóhnSnow@gmail.com J
1 JóhnSnow@gmail.com ó
1 JóhnSnow@gmail.com h
1 JóhnSnow@gmail.com n
1 JóhnSnow@gmail.com S
1 JóhnSnow@gmail.com n
1 JóhnSnow@gmail.com ó
1 JóhnSnow@gmail.com w
.....
Затем вы можете извлечь специальные символы, преобразовав их в VARCHAR
с сопоставлением SQL_Latin1_General_Cp1251_CS_AS
и проверив его в оригинале:
DECLARE @T TABLE (ID INT IDENTITY, Email NVARCHAR(255));
INSERT @T (Email)
VALUES (N'JóhnSnów@gmail.com'), (N'Khãlessi@gmail.com'), ('NedStark@gmail.com');
WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3),
AllCharacters as
( SELECT t.ID,
t.Email,
Character = SUBSTRING(t.Email, n.Number, 1),
Position = n.Number
FROM @T AS t
INNER JOIN Numbers n
ON n.Number < LEN(t.Email)
)
SELECT ac.ID, ac.Character, ac.Position
FROM AllCharacters AS ac
WHERE CONVERT(CHAR(1), ac.Character) COLLATE SQL_Latin1_General_Cp1251_CS_AS <> ac.Character
ORDER BY ac.ID;
Результат
ID Email Character Position
----------------------------------------------------
1 JóhnSnów@gmail.com ó 2
1 JóhnSnów@gmail.com ó 7
2 Khãlessi@gmail.com ã 3
Затем, наконец, при необходимости вы можете использовать XML-расширения для объединения этих символов в один столбец:
DECLARE @T TABLE (ID INT IDENTITY, Email NVARCHAR(255));
INSERT @T (Email)
VALUES (N'JóhnSnów@gmail.com'), (N'Khãlessi@gmail.com'), ('NedStark@gmail.com');
WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) FROM N3),
AllCharacters as
( SELECT t.ID,
t.Email,
Character = SUBSTRING(t.Email, n.Number, 1),
Position = n.Number
FROM @T AS t
INNER JOIN Numbers n
ON n.Number < LEN(t.Email)
), SpecialCharacters AS
( SELECT ac.ID, ac.Character, ac.Position
FROM AllCharacters AS ac
WHERE CONVERT(CHAR(1), ac.Character) COLLATE SQL_Latin1_General_Cp1251_CS_AS <> ac.Character
)
SELECT t.ID,
t.Email,
SpecialCharacters = ISNULL(STUFF(s.SpecialCharacterList.value('.', 'NVARCHAR(255)'), 1, 2, ''), '')
FROM @T AS T
CROSS APPLY
( SELECT CONCAT(N', ', s.Character, '(', Position, ')')
FROM SpecialCharacters AS s
WHERE s.ID = t.ID
ORDER BY Position
FOR XML PATH(''), TYPE
) s (SpecialCharacterList)
ORDER BY ID;
Результат
ID Email SpecialCharacters
------------------------------------------------
1 JóhnSnów@gmail.com ó(2), ó(7)
2 Khãlessi@gmail.com ã(3)
3 NedStark@gmail.com
Кроме того, для ваших нужд может быть лучше хранить в таблице то, что вы считаете специальными символами, а не полагаться на кодовые страницы для конкретных параметров сортировки. Если бы вы это сделали, вам просто нужно изменить эта строка:
WHERE CONVERT(CHAR(1), ac.Character) COLLATE SQL_Latin1_General_Cp1251_CS_AS <> ac.Character
Для:
WHERE EXISTS (SELECT 1 FROM MySpecialCharacterTable AS sct WHERE sct.Character = ac.Character)