quitar hasta especiales codigo charindex caracteres caracter sql-server tsql sql-server-2005 non-ascii-characters

hasta - Encuentre caracteres que no sean ASCII en columnas varchar usando SQL Server



substring sql (8)

Aquí hay una UDF que construí para detectar columnas con caracteres ascii extendidos. Es rápido y puede ampliar el conjunto de caracteres que desea verificar. El segundo parámetro le permite alternar entre verificar cualquier cosa que esté fuera del conjunto de caracteres estándar o permitir un conjunto ampliado:

create function [dbo].[udf_ContainsNonASCIIChars] ( @string nvarchar(4000), @checkExtendedCharset bit ) returns bit as begin declare @pos int = 0; declare @char varchar(1); declare @return bit = 0; while @pos < len(@string) begin select @char = substring(@string, @pos, 1) if ascii(@char) < 32 or ascii(@char) > 126 begin if @checkExtendedCharset = 1 begin if ascii(@char) not in (9,124,130,138,142,146,150,154,158,160,170,176,180,181,183,184,185,186,192,193,194,195,196,197,199,200,201,202,203,204,205,206,207,209,210,211,212,213,214,216,217,218,219,220,221,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,248,249,250,251,252,253,254,255) begin select @return = 1; select @pos = (len(@string) + 1) end else begin select @pos = @pos + 1 end end else begin select @return = 1; select @pos = (len(@string) + 1) end end else begin select @pos = @pos + 1 end end return @return; end

USO:

select Address1 from PropertyFile_English where udf_ContainsNonASCIIChars(Address1, 1) = 1

¿Cómo pueden devolverse las filas con caracteres que no sean ASCII utilizando SQL Server?
Si puede mostrar cómo hacerlo para una columna sería genial.

Estoy haciendo algo como esto ahora, pero no está funcionando

select * from Staging.APARMRE1 as ar where ar.Line like ''%[^!-~ ]%''

Para crédito adicional, si puede abarcar todas las columnas varchar en una tabla, ¡eso sería excepcional! En esta solución, sería bueno devolver tres columnas:

  • El campo de identidad para ese registro. (Esto permitirá que todo el registro sea revisado con otra consulta).
  • El nombre de la columna
  • El texto con el carácter inválido

Id | FieldName | InvalidText | ----+-----------+-------------------+ 25 | LastName | Solís | 56 | FirstName | François | 100 | Address1 | 123 Ümlaut street |

Los caracteres inválidos serían cualquiera fuera del rango de SPACE (32 10 ) a ~ (127 10 )


Aquí hay una solución para la búsqueda de una sola columna usando PATINDEX.
También muestra los caracteres StartPosition, InvalidCharacter y ASCII.

select line, patindex(''%[^ !-~]%'' COLLATE Latin1_General_BIN,Line) as [Position], substring(line,patindex(''%[^ !-~]%'' COLLATE Latin1_General_BIN,Line),1) as [InvalidCharacter], ascii(substring(line,patindex(''%[^ !-~]%'' COLLATE Latin1_General_BIN,Line),1)) as [ASCIICode] from staging.APARMRE1 where patindex(''%[^ !-~]%'' COLLATE Latin1_General_BIN,Line) >0


Este script busca caracteres que no sean ascii en una columna. Genera una cadena de todos los caracteres válidos, aquí codifica el punto 32 a 127. Luego busca las filas que no coinciden con la lista:

declare @str varchar(128) declare @i int set @str = '''' set @i = 32 while @i <= 127 begin set @str = @str + ''|'' + char(@i) set @i = @i + 1 end select col1 from YourTable where col1 like ''%[^'' + @str + '']%'' escape ''|''


Hay una función definida por el usuario disponible en la web ''Parse alfanumérico''. Google UDF analizar alfanumérico y debe encontrar el código para ello. Esta función definida por el usuario elimina todos los caracteres que no se ajustan entre 0-9, az y AZ.

select dodgyColumn from myTable fcc WHERE patindex(''%[^ !-~]%'' COLLATE Latin1_General_BIN,dodgyColumn ) >0

Eso debería traer de vuelta cualquier registro que tenga un last_name con caracteres inválidos para usted ... aunque su pregunta de puntos de bonificación es un desafío un poco más, pero creo que una declaración de caso podría manejarlo. Este es un código poco psíquico, no estoy del todo seguro de si funcionaría.

select dodgyColumn from myTable fcc INNER JOIN dbo.Numbers32k dn ON dn.number<(len(fcc.dodgyColumn )) WHERE ASCII(SUBSTRING(fcc.dodgyColumn , dn.Number, 1))<32 OR ASCII(SUBSTRING(fcc.dodgyColumn , dn.Number, 1))>127

Lo escribí en el buzón del foro ... así que no estoy seguro si funcionará como está, pero debería estar cerca. No estoy seguro de cómo se comportará si un solo registro tiene dos campos con caracteres no válidos tampoco.

Como alternativa, debería ser capaz de cambiar la cláusula from de una sola tabla a una subconsulta que se parece a algo así como:

select dodgyColumn from myTable where dbo.udf_test_ContainsNonASCIIChars(dodgyColumn , 1) = 1

El beneficio aquí es que para cada columna solo tendrá que extender la declaración del sindicato aquí, mientras que necesita poner esa comparación tres veces para cada columna en la versión del estado de cuenta de este script


He estado ejecutando este código poco con éxito

declare @UnicodeData table ( data nvarchar(500) ) insert into @UnicodeData values (N''Horse�'') ,(N''Dog'') ,(N''Cat'') select data from @UnicodeData where data collate LATIN1_GENERAL_BIN != cast(data as varchar(max))

Lo cual funciona bien para columnas conocidas.

Para obtener más crédito, escribí este guión rápido para buscar todas las columnas nvarchar en una tabla determinada para caracteres Unicode.

declare @sql varchar(max) = '''' ,@table sysname = ''mytable'' -- enter your table here ;with ColumnData as ( select RowId = row_number() over (order by c.COLUMN_NAME) ,c.COLUMN_NAME ,ColumnName = ''['' + c.COLUMN_NAME + '']'' ,TableName = ''['' + c.TABLE_SCHEMA + ''].['' + c.TABLE_NAME + '']'' from INFORMATION_SCHEMA.COLUMNS c where c.DATA_TYPE = ''nvarchar'' and c.TABLE_NAME = @table ) select @sql = @sql + ''select FieldName = '''''' + c.ColumnName + '''''', InvalidCharacter = ['' + c.COLUMN_NAME + ''] from '' + c.TableName + '' where '' + c.ColumnName + '' collate LATIN1_GENERAL_BIN != cast('' + c.ColumnName + '' as varchar(max)) '' + case when c.RowId <> (select max(RowId) from ColumnData) then '' union all '' else '''' end + char(13) from ColumnData c -- check -- print @sql exec (@sql)

No soy partidario de SQL dinámico, pero tiene sus aplicaciones para consultas exploratorias como esta.


Para encontrar qué campo tiene caracteres inválidos:

SELECT * FROM Staging.APARMRE1 FOR XML AUTO, TYPE

Puedes probarlo con esta consulta:

SELECT top 1 ''char 31: ''+char(31)+'' (hex 0x1F)'' field from sysobjects FOR XML AUTO, TYPE

El resultado será:

Msg 6841, nivel 16, estado 1, línea 3 FOR XML no pudo serializar los datos para el nodo ''campo'' porque contiene un carácter (0x001F) que no está permitido en XML. Para recuperar esta información usando FOR XML, conviértala a tipo de datos binario, varbinary o de imagen y use la directiva BINARY BASE64.

Es muy útil cuando escribe archivos xml y obtiene el error de caracteres no válidos cuando lo valida.


ejecutando varias soluciones en algunos datos del mundo real: 12M filas varchar longitud ~ 30, alrededor de 9k filas dudosas, sin índice de texto completo en juego, la solución patIndex es la más rápida, y también selecciona la mayoría de las filas.

(recorrió previamente el km para establecer el caché en un estado conocido, ejecutó los 3 procesos, y finalmente ejecutó km nuevamente - las últimas 2 carreras de km dieron tiempos en 2 segundos)

solución patindex de Gerhard Weiss - Runtime 0:38, devuelve 9144 filas

Select * from Staging.APARMRE1 ar where udf_parsealpha(ar.last_name) <> ar.last_name

la solución de números de subcadenas de MT. - Tiempo de ejecución 1:16, devuelto 8996 filas

Select id, case when udf_parsealpha(ar.last_name) <> ar.last_name then ''last name'' when udf_parsealpha(ar.first_name) <> ar.first_name then ''first name'' when udf_parsealpha(ar.Address1) <> ar.last_name then ''Address1'' end, case when udf_parsealpha(ar.last_name) <> ar.last_name then ar.last_name when udf_parsealpha(ar.first_name) <> ar.first_name then ar.first_name when udf_parsealpha(ar.Address1) <> ar.last_name then ar.Address1 end from Staging.APARMRE1 ar where udf_parsealpha(ar.last_name) <> ar.last_name or udf_parsealpha(ar.first_name) <> ar.first_name or udf_parsealpha(ar.Address1) <> ar.last_name

solución udf por Deon Robertson - Runtime 3:47, devuelve 7316 filas

select id,fieldname,value from ( Select id,''last_name'' as ''fieldname'', last_name as ''value'' from Staging.APARMRE1 ar Union Select id,''first_name'' as ''fieldname'', first_name as ''value'' from Staging.APARMRE1 ar ---(and repeat unions for each field) ) where udf_parsealpha(value) <> value


intente algo como esto:

DECLARE @YourTable table (PK int, col1 varchar(20), col2 varchar(20), col3 varchar(20)) INSERT @YourTable VALUES (1, ''ok'',''ok'',''ok'') INSERT @YourTable VALUES (2, ''BA''+char(182)+''D'',''ok'',''ok'') INSERT @YourTable VALUES (3, ''ok'',char(182)+''BAD'',''ok'') INSERT @YourTable VALUES (4, ''ok'',''ok'',''B''+char(182)+''AD'') INSERT @YourTable VALUES (5, char(182)+''BAD'',''ok'',char(182)+''BAD'') INSERT @YourTable VALUES (6, ''BAD''+char(182),''B''+char(182)+''AD'',''BAD''+char(182)+char(182)+char(182)) --if you have a Numbers table use that, other wise make one using a CTE ;WITH AllNumbers AS ( SELECT 1 AS Number UNION ALL SELECT Number+1 FROM AllNumbers WHERE Number<1000 ) SELECT pk, ''Col1'' BadValueColumn, CONVERT(varchar(20),col1) AS BadValue --make the XYZ in convert(varchar(XYZ), ...) the largest value of col1, col2, col3 FROM @YourTable y INNER JOIN AllNumbers n ON n.Number <= LEN(y.col1) WHERE ASCII(SUBSTRING(y.col1, n.Number, 1))<32 OR ASCII(SUBSTRING(y.col1, n.Number, 1))>127 UNION SELECT pk, ''Col2'' BadValueColumn, CONVERT(varchar(20),col2) AS BadValue --make the XYZ in convert(varchar(XYZ), ...) the largest value of col1, col2, col3 FROM @YourTable y INNER JOIN AllNumbers n ON n.Number <= LEN(y.col2) WHERE ASCII(SUBSTRING(y.col2, n.Number, 1))<32 OR ASCII(SUBSTRING(y.col2, n.Number, 1))>127 UNION SELECT pk, ''Col3'' BadValueColumn, CONVERT(varchar(20),col3) AS BadValue --make the XYZ in convert(varchar(XYZ), ...) the largest value of col1, col2, col3 FROM @YourTable y INNER JOIN AllNumbers n ON n.Number <= LEN(y.col3) WHERE ASCII(SUBSTRING(y.col3, n.Number, 1))<32 OR ASCII(SUBSTRING(y.col3, n.Number, 1))>127 order by 1 OPTION (MAXRECURSION 1000)

SALIDA:

pk BadValueColumn BadValue ----------- -------------- -------------------- 2 Col1 BA¶D 3 Col2 ¶BAD 4 Col3 B¶AD 5 Col1 ¶BAD 5 Col3 ¶BAD 6 Col1 BAD¶ 6 Col2 B¶AD 6 Col3 BAD¶¶¶ (8 row(s) affected)