SQL Server: Search all tables for a particular GUID

前端 未结 5 2076
说谎
说谎 2021-02-03 23:10

i came across the need to cleanse some data, and i need to find some particular guids (i.e. uniqueidentifiers) in SQL Server°.

i\'ve come up with a stor

5条回答
  •  借酒劲吻你
    2021-02-03 23:39

    You could defer the EXEC until your cursor loop is done. Then, just track the table name inside your loop and if it's the same, add an OR, otherwise end your SELECT and start a new one.

    DECLARE @lasttable varchar(255);
    SET @lasttable='';
    FETCH NEXT FROM abc INTO @tableName, @columnName;
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
       IF(@lasttable=@tablename) BEGIN
           SET @szQuery = @szQuery + ' OR [' + @columnName + ']=''' + CAST(@searchValue AS varchar(50)) + '''';
       END ELSE BEGIN
           SET @lasttable = @tablename;
           SET @szQuery = @szQuery + 
             'SELECT '''+@tableName+''' AS TheTable, '''+@columnName+''' AS TheColumn '+
             'FROM '+@tableName+' '+
             'WHERE '+@columnName+' = '''+CAST(@searchValue AS varchar(50))+''''
       END
       FETCH NEXT FROM abc INTO @tableName, @columnName;
    END
    PRINT @szQuery;
    EXEC (@szQuery);
    

    You could also create the stored procedure to build a VIEW that does a UNION ALL of all tables and uniqueidentifier fields. Something with a schema like this:

    CREATE VIEW all_uuids AS (
        SELECT 'prices' AS tablename, 'BookGUID' as fieldname, ID as primarykey, BookGUID AS guid FROM prices
        UNION ALL SELECT 'prices', 'AuthorGUID', ID, AuthorGUID FROM prices
        UNION ALL SELECT 'othertable', 'otherfield', ID, otherfield FROM othertable
        )
    

    Then, you just need to perform a single SELECT statement on this reusable VIEW to get all of the matching GUIDs. To search within a single table, use a correlated subquery, e.g.:

    SELECT * FROM prices WHERE EXISTS (SELECT null FROM all_uuids u WHERE u.primarykey=prices.id AND u.guid=@searchfor AND u.tablename='prices')
    

    That will search across all GUID fields in the prices table. SQL Server is smart enough to not go looking through other tables, and it uses your existing tables' indexes.

    By re-using a single view, you only have to go looping through information_schema when you change your schema, not with every query, and the results of a view can be joined more readily than the results of a stored procedure.


    Answer

    Original posters final solution, based on this answer:

    CREATE PROCEDURE dbo.FindGUID @searchValue uniqueidentifier AS
    
    /*
        Search all tables in the database for a guid
    
        Revision History
        6/9/2009: Initally created
        6/10/2009: Build or clause of multiple columns on one table
    */
    
    --DECLARE @searchValue uniqueidentifier
    --SET @searchValue = '{2A6814B9-8261-452D-A144-13264433864E}'
    
    DECLARE abc CURSOR FOR
        SELECT 
            c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME
        FROM INFORMATION_SCHEMA.Columns c
            INNER JOIN INFORMATION_SCHEMA.Tables t
            ON c.TABLE_NAME = t.TABLE_NAME
            AND t.TABLE_TYPE = 'BASE TABLE'
        WHERE DATA_TYPE = 'uniqueidentifier'
    
    DECLARE @tableSchema varchar(200)
    DECLARE @tableName varchar(200)
    DECLARE @columnName varchar(200)
    DECLARE @szQuery varchar(8000)
    SET @szQuery = ''
    
    DECLARE @lasttable varchar(255);
    SET @lasttable='';
    
    OPEN ABC
    
    FETCH NEXT FROM abc INTO @tableSchema, @tableName, @columnName;
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
       IF(@lasttable=@tablename) 
       BEGIN
          SET @szQuery = @szQuery + ' OR [' + @columnName + ']=''' + CAST(@searchValue AS varchar(50)) + '''';
       END 
       ELSE 
       BEGIN
           SET @lasttable = @tablename;
    
           IF @szQuery <> '' 
           BEGIN
              PRINT @szQuery
              EXEC ('IF EXISTS (' + @szQuery + ') BEGIN ' + @szQuery + ' END');
           END
    
           SET @szQuery = 
             'SELECT '''+@tableSchema+'.'+@tableName+''' AS TheTable, '''+@columnName+''' AS TheColumn '+
             'FROM '+@tableName+' '+
             'WHERE '+@columnName+' = '''+CAST(@searchValue AS varchar(50))+''''
       END
       FETCH NEXT FROM abc INTO @tableSchema, @tableName, @columnName;
    END
    
    CLOSE abc
    DEALLOCATE abc
    
    IF @szQuery <> '' 
    BEGIN
        PRINT @szQuery
        EXEC ('IF EXISTS (' + @szQuery + ') BEGIN ' + @szQuery + ' END');
    END
    GO
    

提交回复
热议问题