在SQL Server数据库中搜索控制字符

时间:2016-12-15 11:41:42

标签: sql-server tsql search

我正在寻找MSSQL数据库中不需要的控制字符。

我目前使用的存储过程是针对我需要搜索的数据库创建的,但这只能在搜索简单字符或字符串时起作用。请参阅下面的步骤(这是第一次从本网站收集)

CREATE PROC SearchAllTables
(
@SearchStr nvarchar(100)
)
AS
BEGIN

-- Creates a Stored Procedure for the database
-- When running the procedure, set the @SearchStr parameter to the character you are searching for

CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))

SET NOCOUNT ON

DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
SET  @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')

WHILE @TableName IS NOT NULL
BEGIN
SET @ColumnName = ''
SET @TableName = 
(
    SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
    FROM    INFORMATION_SCHEMA.TABLES
    WHERE       TABLE_TYPE = 'BASE TABLE'
        AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
        AND OBJECTPROPERTY(
                OBJECT_ID(
                    QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
                     ), 'IsMSShipped'
                       ) = 0
)

WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
BEGIN
    SET @ColumnName =
    (
        SELECT MIN(QUOTENAME(COLUMN_NAME))
        FROM    INFORMATION_SCHEMA.COLUMNS
        WHERE       TABLE_SCHEMA    = PARSENAME(@TableName, 2)
            AND TABLE_NAME  = PARSENAME(@TableName, 1)
            AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
            AND QUOTENAME(COLUMN_NAME) > @ColumnName
    )

    IF @ColumnName IS NOT NULL
    BEGIN
        INSERT INTO #Results
        EXEC
        (
            'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
            FROM ' + @TableName + ' (NOLOCK) ' +
            ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
        )
END
END 
END

SELECT ColumnName, ColumnValue FROM #Results
END

现在,我需要更改此设置以允许我搜索控制字符列表:

    '%['
                      + CHAR(0)+CHAR(1)+CHAR(2)+CHAR(3)+CHAR(4)
                      + CHAR(5)+CHAR(6)+CHAR(7)+CHAR(8)+CHAR(9)
                      + CHAR(10)+CHAR(11)+CHAR(12)+CHAR(13)+CHAR(14)
                      + CHAR(15)+CHAR(16)+CHAR(17)+CHAR(18)+CHAR(19)
                      + CHAR(20)+CHAR(21)+CHAR(22)+CHAR(23)+CHAR(24)
                      + CHAR(25)+CHAR(26)+CHAR(27)+CHAR(28)+CHAR(29)
                      + CHAR(30)+CHAR(31)+CHAR(127)
                      + ']%',

现在,现有的程序将不允许我将其用作搜索字符串,即使使用单个控制字符也无法正确搜索,例如CHAR(28)

USE [DBNAME]
GO

DECLARE @return_value int

EXEC    @return_value = [dbo].[SearchAllTables]
        @SearchStr = N'CHAR (28)'

SELECT  'Return Value' = @return_value

GO

在上面的示例中从@SearchStr中删除N''会导致错误消息:

  

'28'附近的语法不正确

任何人都可以帮助调整此过程以允许搜索控制字符吗?

3 个答案:

答案 0 :(得分:2)

我会选择动态CharIndex()。请考虑以下

Declare @ColumnName varchar(25)='[SomeField]'
Declare @SearchFor  nvarchar(max) ='CHAR(0),CHAR(1),CHAR(2),CHAR(3),CHAR(4),CHAR(5),CHAR(6),CHAR(7),CHAR(8),CHAR(9),CHAR(10),CHAR(11),CHAR(12),CHAR(13),CHAR(14),CHAR(15),CHAR(16),CHAR(17),CHAR(18),CHAR(19),CHAR(20),CHAR(21),CHAR(22),CHAR(23),CHAR(24),CHAR(25),CHAR(26),CHAR(27),CHAR(28),CHAR(29),CHAR(30),CHAR(31),CHAR(127)'
Set @SearchFor = 'CharIndex('+Replace(@SearchFor,',',','+@ColumnName+')+CharIndex(')+','+@ColumnName+')'

所以你的动态在哪里看起来像这样

' WHERE ' + @SearchFor + '>0'

仅举例说明,@ SearchFor字符串看起来像这样

CharIndex(CHAR(0),[SomeField])+CharIndex(CHAR(1),[SomeField])+...+CharIndex(CHAR(31),[SomeField])+CharIndex(CHAR(127),[SomeField])

答案 1 :(得分:1)

看起来QUOTENAME正在为你打破一切。当您尝试使用某些字符时 - 例如char(0) - 它会返回NULL。因此,您可能最好自己手动输入单引号。

这意味着您需要更改此部分:

    INSERT INTO #Results
    EXEC
    (
        'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
        FROM ' + @TableName + ' (NOLOCK) ' +
        ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
    )

到此:

    INSERT INTO #Results
    EXEC
    (
        'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
        FROM ' + @TableName + ' (NOLOCK) ' +
        ' WHERE ' + @ColumnName + ' LIKE ''' + @SearchStr + '''  -- Note the use of @SearchStr (Not @SearchStr2) and the additional quotes to wrap your search string in. 
    )

应该允许您使用%[...]%模式匹配语法。

答案 2 :(得分:0)

<强>关注

  • 性能

您可能知道,参数开头和结尾的通配符(%)会阻止SARG根本使用任何索引(即使它声称使用INDEX SCAN )因为SQL Server不知道值将在何处。在最糟糕的情况下,它甚至可能会出现错误的区域!

更严重的是,你发起的最后一个EXEC语句将使SQL Server运行起来。尽管你可能会想到,SQL Server执行时初始化变量。这意味着,当优化器处于执行查询计划的中间时,优化器将继续运行,并且最终可能会多次更改!

  

我的一个DB上发生的可能释放的示例a   一个月前,一个可怕的新插件运行一个简单的查询寻找   在1的大表上只有两个严重参数化谓词的一行   百万行。然而,优化器吞噬了数以万亿计的IO秒   几秒钟的问题(对于州长来说查询来得太快了)   并通过网络发送 20亿行 PER QUERY 。   可悲的是,那天的问题被僵尸,只有500个一排   我的数据库中的结果集反复运行,它降低了我们的   服务器

  • 隔离和交易

随意猜测,期望锁定问题并吞噬资源。诸如UPDATESREINDEXINGALTER语句等主要操作将被迫等待或将您的查询踢到路边。即使使用READ UNCOMMITTED也无法避免一些阻塞问题。

新方法

您列出的所有字符既不是字母也不是数字,而是从前端应用程序流入的无意义垃圾(到SQL Server)。我注意到你排除了Microsoft System Tables,那么你的数据流来自何处以及如何在整个数据库中传播?谁有过错?系统,用户和设计师如何在混乱中发挥作用?

此服务器是OLTP还是READ重?您的组织是否没有强大的SSISETL系统来防止垃圾在您的服务器上造成严重破坏?

  • 数据库约束

确实,您的应用程序在发送数据之前未能预先清理数据的原因是什么?当它确实达到数据库级别时,为什么我们不能同时使用DATA TYPETABLE CONSTRAINTS?简单的解决方案,例如使用DATE而不是VARCHAR来存储日期,添加规范化而不是存储blob以将读取繁重的表与写入密集的表格隔离开来,这可以说明改进的奇迹。

承认,使用CHECK CONSTRAINTS会导致INSERT语句的效果呈指数级下降,因此您可能需要考虑更大的影响。

预防性与规定性

表面上看,我可以编写一个可以解决当前问题的查询(在另一个Stored Proc中封装EXEC语句可以启用正确的参数嗅探),我们需要多写一些并编写更少的代码。 你的程序现在很糟糕,即使我们穿着衣服也一直都是。它掩盖了这些控制角色如何首先到达那里的真正问题,并迫使对你的糟糕系统进行昂贵的查询。

你的表如何工作,规范化,基数的关系应该对你有意义,这样你不仅可以区分表的类型,还可以区分它们拥有的那些特定的列。您当前的麻烦对我的许多数据库来说都是灾难性的,这些数据库的大小可以达到1.5+太字节

您收集的要求越多,答案就越好。哎呀,即使完全为ETL设置数据库也会优于您当前的解决方案。即使你最终仍然运行类似的查询,至少你会将你的列和表的列表缩短到一分钟,可理解的列表,而不是盲目地给你公司的每个人带来痛苦。

祝福!