Как найти символы Unicode/ не ASCII в поле NTEXT в таблице SQL Server 2005?
У меня есть таблица с несколькими тысячами строк. Поля описания и сводки - это NTEXT, и иногда в них есть символы не-ASCII. Как я могу найти все строки с не ASCII-символами?
9 ответов
Иногда я использовал это выражение "cast", чтобы найти "странные" символы
select
*
from
<Table>
where
<Field> != cast(<Field> as varchar(1000))
Сначала создайте строку со всеми символами, которые вас не интересуют (в примере используется диапазон 0x20 - 0x7F или 7 бит без управляющих символов). Каждый символ имеет префикс |, чтобы использовать его в последующем предложении escape.
-- Start with tab, line feed, carriage return
declare @str varchar(1024)
set @str = '|' + char(9) + '|' + char(10) + '|' + char(13)
-- Add all normal ASCII characters (32 -> 127)
declare @i int
set @i = 32
while @i <= 127
begin
-- Uses | to escape, could be any character
set @str = @str + '|' + char(@i)
set @i = @i + 1
end
Следующий фрагмент ищет любой символ, которого нет в списке. % Соответствует 0 или более символам. [] Соответствует одному из символов внутри [], например, [abc] соответствует либо a, b, либо c. ^ Отрицает список, например [^abc] будет соответствовать чему-либо, кроме a, b или c.
select *
from yourtable
where yourfield like '%[^' + @str + ']%' escape '|'
Экранирующий символ необходим, потому что в противном случае поиск таких символов, как], % или _, испортил бы выражение LIKE.
Надеюсь, что это полезно, и благодаря комментарию JohnFX на другой ответ.
Вот, пожалуйста.
SELECT *
FROM Objects
WHERE
ObjectKey LIKE '%[^0-9a-zA-Z !"#$%&''()*+,\-./:;<=>?@\[\^_`{|}~\]\\]%' ESCAPE '\'
Технически, я считаю, что NCHAR(1) является действительным символом ASCII, ЕСЛИ И ТОЛЬКО ЕСЛИ UNICODE(@NChar) < 256 и ASCII(@NChar) = UNICODE(@NChar), хотя это может быть не совсем то, что вы хотели. Поэтому это будет правильным решением:
;With cteNumbers as
(
Select ROW_NUMBER() Over(Order By c1.object_id) as N
From sys.system_columns c1, sys.system_columns c2
)
Select Distinct RowID
From YourTable t
Join cteNumbers n ON n <= Len(CAST(TXT As NVarchar(MAX)))
Where UNICODE(Substring(TXT, n.N, 1)) > 255
OR UNICODE(Substring(TXT, n.N, 1)) <> ASCII(Substring(TXT, n.N, 1))
Это также должно быть очень быстро.
Возможно, это не лучшее решение, но, возможно, такой запрос:
SELECT *
FROM yourTable
WHERE yourTable.yourColumn LIKE '%[^0-9a-zA-Z]%'
Замените выражение "0-9a-zA-Z" чем-то, что захватывает полный набор ASCII (или подмножество, которое содержат ваши данные).
Я начал с решения @CC1960, но нашел интересный вариант использования, который привел к сбою. Кажется, что SQL Server будет приравнивать определенные символы Unicode к их не-Unicode приближениям. Например, SQL Server считает символ Unicode "запятой полной ширины" ( http://www.fileformat.info/info/unicode/char/ff0c/index.htm) так же, как стандартная запятая ASCII при сравнении в предложении WHERE.
Чтобы обойти это, пусть SQL Server сравнивает строки как двоичные. Но помните, что двоичные файлы nvarchar и varchar не совпадают (16-разрядные против 8-разрядных), поэтому перед повторным сравнением двоичных файлов вам необходимо снова преобразовать varchar в nvarchar:
select *
from my_table
where CONVERT(binary(5000),my_table.my_column) != CONVERT(binary(5000),CONVERT(nvarchar(1000),CONVERT(varchar(1000),my_table.my_column)))
Если вы ищете определенный символ Unicode, вы можете использовать что-то вроде ниже.
select Fieldname from
(
select Fieldname,
REPLACE(Fieldname COLLATE Latin1_General_BIN,
NCHAR(65533) COLLATE Latin1_General_BIN,
'CustomText123') replacedcol
from table
) results where results.replacedcol like '%CustomText123%'
Мой предыдущий ответ вводил в заблуждение данные UNICODE/non-UNICODE. Вот решение, которое должно работать во всех ситуациях, хотя я все еще сталкиваюсь с некоторыми аномалиями. Кажется, что некоторые не-ASCII символы юникода для символов верхнего индекса путают с действительным символом числа. Вы можете поиграть с сопоставлениями, чтобы обойти это.
Надеюсь, у вас уже есть таблица чисел в вашей базе данных (они могут быть очень полезны), но на всякий случай я включил код, чтобы частично его заполнить.
Вам также может понадобиться поиграться с числовым диапазоном, поскольку символы Юникода могут выходить за пределы 255.
CREATE TABLE dbo.Numbers
(
number INT NOT NULL,
CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (number)
)
GO
DECLARE @i INT
SET @i = 0
WHILE @i < 1000
BEGIN
INSERT INTO dbo.Numbers (number) VALUES (@i)
SET @i = @i + 1
END
GO
SELECT *,
T.ID, N.number, N'%' + NCHAR(N.number) + N'%'
FROM
dbo.Numbers N
INNER JOIN dbo.My_Table T ON
T.description LIKE N'%' + NCHAR(N.number) + N'%' OR
T.summary LIKE N'%' + NCHAR(N.number) + N'%'
and t.id = 1
WHERE
N.number BETWEEN 127 AND 255
ORDER BY
T.id, N.number
GO
- Это очень, очень неэффективный способ сделать это, но должно быть хорошо для маленьких столов. Он использует вспомогательную таблицу чисел согласно Ицику Бен-Гану и просто - ищет символы с установленным битом 7.
SELECT *
FROM yourTable as t
WHERE EXISTS ( SELECT *
FROM msdb..Nums as NaturalNumbers
WHERE NaturalNumbers.n < LEN(t.string_column)
AND ASCII(SUBSTRING(t.string_column, NaturalNumbers.n, 1)) > 127)