У меня есть следующая таблица:
Select
name,
address,
description
from dbo.users
Я хотел бы найти во всей этой таблице любые символы UNICODE, но не ASCII. Это возможно?
У меня есть следующая таблица:
Select
name,
address,
description
from dbo.users
Я хотел бы найти во всей этой таблице любые символы UNICODE, но не ASCII. Это возможно?
Если вы хотите определить, есть ли в столбце NVARCHAR
/ NCHAR
/ NTEXT
какие-либо символы, которые нельзя преобразовать в VARCHAR
, вам необходимо преобразовать в VARCHAR
, используя _BIN2
вариант сопоставления, используемый для этого конкретного столбца. Например, если в определенном столбце используется Albanian_100_CI_AS
, для теста следует указать Albanian_100_BIN2
. Причина использования сопоставления _BIN2
заключается в том, что недвоичные сопоставления будут находить только те экземпляры, где есть хотя бы один символ, который вообще не имеет никакого сопоставления в кодовой странице и, таким образом, преобразуется в ?
. Но недвоичные сопоставления не улавливают экземпляры, в которых есть символы, которые не имеют прямого сопоставления с кодовой страницей, а вместо этого имеют «наилучшее соответствие». Например, символ верхнего индекса 2, ²
, имеет прямое сопоставление с кодовой страницей 1252, так что здесь определенно нет проблем. С другой стороны, у него нет прямого сопоставления в кодовой странице 1250 (используемой албанскими сопоставлениями), но у него есть «наилучшее соответствие», которое преобразует его в обычный 2
. Проблема с небинарной сортировкой заключается в том, что 2
будет равняться ²
, и поэтому она не будет зарегистрирована как строка, которая не может быть преобразована в VARCHAR
. Например:
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE French_100_CI_AS); -- Code Page 1252
-- ²
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS); -- Code Page 1250
-- 2
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS)
WHERE N'²' <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS));
-- (no rows returned)
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2)
WHERE N'²' <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2));
-- 2
В идеале вы должны явно преобразовать обратно в NVARCHAR
, чтобы код ясно понимал, что он делает, хотя, если этого не сделать, все равно будет неявно преобразовано обратно в NVARCHAR
, поэтому поведение будет одинаковым в любом случае.
Обратите внимание, что используются только MAX
типов. Не используйте NVARCHAR(4000)
или VARCHAR(4000)
, иначе вы можете получить ложные срабатывания из-за усечения данных в столбцах NVARCHAR(MAX)
.
Таким образом, с точки зрения примера кода в вопросе запрос будет (при условии, что используется сопоставление Latin1_General
):
SELECT usr.*
FROM dbo.[users] usr
WHERE usr.[name] <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), usr.[name] COLLATE Latin1_General_100_BIN2))
OR usr.[address] <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), usr.[address] COLLATE Latin1_General_100_BIN2))
OR usr.[description] <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), usr.[description] COLLATE Latin1_General_100_BIN2));
Вы можете найти символы, отличные от ASCII, довольно просто:
SELECT NAME, ADDRESS, DESCRIPTION
FROM DBO.USERS
WHERE NAME != CAST(NAME AS VARCHAR(4000))
OR ADDRESS != CAST(ADDRESS AS VARCHAR(4000))
OR DESCRIPTION != CAST(DESCRIPTION AS VARCHAR(4000))
SELECT ('vsdǣf' = CAST('vsdǣf' AS VARCHAR(4000)))
...работает
- person whytheq; 23.04.2015
Насколько я могу судить, встроенной функции для этого нет. Подход грубой силы состоит в том, чтобы передать каждый символ в ascii
, а затем передать результат в char
и проверить, возвращает ли он '?', что означало бы, что символ находится вне допустимого диапазона. Вы можете написать UDF с приведенным ниже кодом в качестве ссылки, но я думаю, что это очень неэффективное решение:
declare @i int = 1
declare @x nvarchar(10) = N'vsdǣf'
declare @result nvarchar(100) = N''
while (@i < len(@x))
begin
if char(ascii(substring(@x,@i,1))) = '?'
begin
set @result = @result + substring(@x,@i,1)
end
set @i = @i+1
end
select @result