Search all columns of a table for a value?

后端 未结 9 1525
自闭症患者
自闭症患者 2021-01-17 15:36

I\'ve looked for an answer to this, but all I can find is people asking how to search all columns of ALL tables in a database for a value. I just want to search all columns

相关标签:
9条回答
  • 2021-01-17 16:33

    I modified this stored proc to take a table name as the second parameter and just search that table for the data:

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SearchOneTable]') AND type in (N'P', N'PC'))
    DROP PROCEDURE [dbo].[SearchOneTable]
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROC [dbo].[SearchOneTable]
    (
        @SearchStr nvarchar(100) = 'A',
        @TableName nvarchar(256) = 'dbo.Alerts'
    )
    AS
    BEGIN
    
        CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))
    
        --SET NOCOUNT ON
    
        DECLARE @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
        SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')
        --SET @SearchStr2 = QUOTENAME(@SearchStr, '''') --exact match
        SET @ColumnName = ' '
    
    
            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 
        SELECT ColumnName, ColumnValue FROM #Results
    END
    
    
    GO
    
    0 讨论(0)
  • 2021-01-17 16:35

    Here is a solution that, like @Decker97's approach, figures out from metadata which columns are eligible for text search. Assumes 2005+ for use of XML PATH as well as sys.columns, sys.tables, etc. Supports TEXT/NTEXT/CHAR/NCHAR/VARCHAR/NVARCHAR, and even puts the leading N on the search string where appropriate. Does not support XML columns. What it does do slightly differently is that it returns a single resultset for each table, not for every single column, so you only get one row per actual table row even if multiple columns match. If the goal is to understand how it works rather than simply having a solution, it will probably take a bit more than this... perhaps I should blog about this problem (I should probably not be lazy and actually build the column lists instead of just using SELECT *).

    DECLARE @SearchTerm NVARCHAR(32) = 'foo';
    
    DECLARE @TableName NVARCHAR(128) = NULL;
    
    SET NOCOUNT ON;
    
    DECLARE @s NVARCHAR(MAX) = '';
    
    WITH [tables] AS
    (
        SELECT [object_id] 
            FROM sys.tables AS t
            WHERE (name = @TableName OR @TableName IS NULL)
            AND EXISTS
            (
                SELECT 1 
                    FROM sys.columns
                    WHERE [object_id] = t.[object_id]
                    AND system_type_id IN (35,99,167,175,231,239)
            )
    )
    SELECT @s = @s + 'SELECT ''' 
        + REPLACE(QUOTENAME(OBJECT_SCHEMA_NAME([object_id])),'''','''''')
        + '.' + REPLACE(QUOTENAME(OBJECT_NAME([object_id])), '''','''''')
        + ''',* FROM ' + QUOTENAME(OBJECT_SCHEMA_NAME([object_id]))
        + '.' + QUOTENAME(OBJECT_NAME([object_id])) + ' WHERE ' + 
        (
            SELECT QUOTENAME(name) + ' LIKE ' + CASE 
                WHEN system_type_id IN (99,231,239) 
                THEN 'N' ELSE '' END
                + '''%' + @SearchTerm + '%'' OR '
            FROM sys.columns
            WHERE [object_id] = [tables].[object_id]
            AND system_type_id IN (35,99,167,175,231,239)
            ORDER BY name
            FOR XML PATH(''), TYPE
    ).value('.[1]', 'nvarchar(max)') + CHAR(13) + CHAR(10)
    FROM [tables];
    
    SELECT @s = REPLACE(@s,' OR ' + CHAR(13),';' + CHAR(13));
    
    /*
        make sure you use Results to Text and adjust Tools / Options / 
        Query Results / SQL Server / Results to Text / Maximum number
        of characters if you want a chance at trusting this output 
        (the number of tables/columns will certainly have the ability
        to exceed the output limitation)
    */
    
    SELECT @s;
    -- EXEC sp_executeSQL @s;
    
    0 讨论(0)
  • 2021-01-17 16:35

    Cutesie little work-around that involves a bit less copy-paste, since the command can be produced easily using queries.

    Invert the IN operator in a WHERE clause as VALUE IN <fields> (as opposed to the more common use case of FIELD IN <values>).

    SELECT col_1, col_2, ... , col_n 
    FROM <table>
    WHERE CAST(<value> AS varchar(max)) IN 
       (
       CAST(col_1 AS varchar(max)),
       CAST(col_2 AS varchar(max)),
       ...,
       CAST(col_n AS varchar(max))
       )
    

    Since varchar is a pretty malleable data type, this becomes pretty foolproof (you can throw ISNULL/NULLIF to modify as needed), and depending on the use case can probably be used across more than one search value.

    A more robust solution, using dynamic execution and PL/SQL would be to write a procedure to dynamically build a view of the target table (via reading e.g. MySQL's information_schema schema, Oracle's SYS schema, etc.), constrained to a where clause containing the input string hard-coded into a series of 'OR'-concatenated/IN clauses for filter conditions.

    0 讨论(0)
提交回复
热议问题