2016-12-15 73 views
1

我正在尋找MSSQL數據庫中不需要的控制字符。在SQL Server數據庫中搜索控制字符

我目前使用的存儲過程是根據我需要搜索的數據庫創建的,但這隻在搜索簡單字符或字符串時才起作用。見下面的步驟,因爲它代表(這是第一次從這個網站上收集)

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'

任何人都可以用幫助一種適應此過程的方法,以允許搜索控制字符?

+0

我很困惑你試圖完成什麼。您希望防止或需要來自對象名稱和列名稱的控制字符?爲什麼你的代碼如此複雜?你所關心的是檢查給予表和列的名稱 –

+0

我試圖在給定數據庫的任何行中查找控制字符。頂部的過程旨在搜索數據庫的每個表中的一個或多個字符。 – KEW

+0

再次在原理圖或每列的實際值?後者是一種完全不同的方法 –

回答

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

我會選擇一個動態的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,',',','[email protected]+')+CharIndex(')+','[email protected]+')' 

那麼您的動態哪裏會是這個樣子

' WHERE ' + @SearchFor + '>0' 

只是爲了說明,@SearchFor字符串應該是這樣

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

關注

  • 性能

正如你可能知道,通配符(%)在開始和爭論的結束防止您SARG使用任何指標都作爲SQL Server沒有(哪怕它聲稱使用)想法的價值將在哪裏。在最壞的情況下,它甚至可能會出現在錯誤的地方!

更加嚴重的是,您最後發佈的EXEC聲明將使SQL Server無法運行。儘管你可能會認爲,SQL Server初始化變量在執行時間。意思是說,優化程序在執行查詢計劃的過程中仍會繼續運行,並且最終可能會多次更改!

的可能被釋放的一個例子發生在我的DB的一個 一個月前,其中一個可怕的新的插件進行了簡單的查詢只有兩個嚴重參數謂詞上一大桌的1尋找 一行 萬行。然而,優化吞沒IO小號萬億在幾秒鐘內 事項(查詢來了又走的太快了省長) 並通過網絡發送2十億行每次查詢。 不幸的是,該問題當天發生殭屍,並且在我的數據庫中只有500個一行 結果集反覆運行,它使我們的 服務器失效。

  • 分離交易

胡亂猜測,期望有鎖定問題和吞噬資源。主要操作如UPDATESREINDEXINGALTER語句將被強制等待或將您的查詢踢到路邊。即使使用READ UNCOMMITTED也不會讓你免於某些阻塞問題。

的新途徑

所有你列出的既不是字母也不是數字,但毫無意義的垃圾(到SQL Server),這些字符是從前端應用流入。我注意到你排除了Microsoft System Tables,那麼你的數據流從哪裏來,它如何在整個數據庫中傳播?誰有錯?系統,用戶和設計師如何在混亂中扮演角色?

這臺服務器是OLTP還是READ很重?你的組織沒有一個有能力的SSIS,ETL系統來防止垃圾對你的服務器造成嚴重破壞?

  • 數據庫約束

穩妥,有什麼理由不你的應用程序無法在發送之前預先清理數據?當它達到數據庫級別時,爲什麼我們不能同時使用DATA TYPETABLE CONSTRAINTS來獲得我們的優勢?簡單的解決方案,如使用DATE而不是VARCHAR來存儲日期,添加標準化而不是存儲blob以將讀取繁重的表與繁重的寫入隔離可以改善奇蹟。

無可否認,使用CHECK CONSTRAINTS可能會導致您的INSERT語句的性能呈指數級下降,因此您可能需要考慮更大的影響。

預防性VS處方

從表面上看,我可以寫,將解決你的當前問題(封裝EXEC語句在另一個Stored Proc能夠正確參數嗅探),我們需要問越來越少寫代碼的查詢。 你的程序現在很糟糕,並且將永遠是,即使我們穿着窗口服裝。它掩蓋了這些控制角色如何到達那裏的真正問題,並迫使您對您的窮人系統進行昂貴的查詢。

你的表格如何工作,規範化,基數對你來說意味着什麼,所以你不僅可以區分表格類型,還可以區分它們擁有的特定列。您目前遇到的麻煩對於我的很多數據庫來說都是災難性的,可能會達到1.5+太字節以上

您越是收集您的要求,您的答案就越好。哎呀,即使完全爲ETL設置數據庫也會比當前的解決方案更優越。即使您最終還是運行了一個類似的查詢,至少您會將列表和表格的列表縮短爲一分鐘,可理解的列表,而不是盲目地給公司中的每個人造成痛苦。

祝願!

+0

你甚至可能會發現使用OOP語言來處理逐行轉換是優越的(C++檢查字母字符)。如果這真的很糟糕,那麼使用ETL(提取,轉換,加載)方法將快上百萬倍並且​​高效。 –