Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

SQL Server - Изберете колони, които отговарят на определени условия?

Създадох съхранена процедура за вас.

Тази процедура изследва MSSQL мета, за да изгради динамичен SQL низ, който връща резултат, съдържащ имена на колони N и техните стойности V и съответния ключ на ред K от която е извлечена тази стойност за определена таблица.

Когато това се изпълни, резултатите се съхраняват в глобална временна таблица, наречена ##ColumnsByValue, която след това може да бъде заявена директно.

Създайте GetColumnsByValue съхранена процедура, като изпълните този скрипт:

-- =============================================
-- Author:      Ben Roberts ([email protected])
-- Create date: 22 Mar 2013
-- Description: Returns the names of columns that contain the specified value, for a given row
-- =============================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID ( 'dbo.GetColumnsByValue', 'P' ) IS NOT NULL 
    DROP PROCEDURE dbo.GetColumnsByValue;
GO
CREATE PROCEDURE dbo.GetColumnsByValue
    -- Add the parameters for the stored procedure here
    @idColumn sysname,
    @valueToFind nvarchar(255), 
    @dbName sysname,
    @tableName sysname,
    @schemaName sysname,
    @debugMode int = 0

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @SQL nvarchar(max);
    DECLARE @SQLUnion nvarchar(max);
    DECLARE @colName sysname;
    DECLARE @dbContext nvarchar(256);
    DECLARE @Union nvarchar(10);

    SELECT @dbContext = @dbName + '.' + @schemaName + '.sp_executeSQL';
    SELECT @SQLUnion = '';
    SELECT @Union = '';

    IF OBJECT_ID ( 'tempdb..##GetColumnsByValueIgnoreList') IS NULL -- no columns to ingore have been specified, need to create an empty list.
    BEGIN
        CREATE TABLE ##GetColumnsByValueIgnoreList (column_name nvarchar(255));
    END

    DECLARE DBcursor CURSOR FOR
        SELECT 
            COLUMN_NAME
        FROM 
            INFORMATION_SCHEMA.COLUMNS
        WHERE 
            TABLE_NAME = @tableName 
            AND 
            TABLE_SCHEMA = @schemaName;

    OPEN DBcursor; 
        FETCH DBcursor INTO @colName;
        WHILE (@@FETCH_STATUS = 0)
        BEGIN
            IF (
                @colName != @idColumn
                AND
                @colName NOT IN (SELECT column_name FROM ##GetColumnsByValueIgnoreList)
            )
            BEGIN
                SELECT @SQL = 'SELECT '[email protected]+' as K, '''[email protected]+''' as N, ' [email protected]+ ' as V FROM ' + @dbName + '.' + @schemaName + '.' + @tableName;
                --PRINT @SQL;
                SELECT @SQLUnion = @SQL + @Union + @SQLUnion;
                SELECT @Union = ' UNION ';
            END
            FETCH  DBcursor INTO @colName;
        END; -- while
    CLOSE DBcursor; DEALLOCATE DBcursor;

    IF (@debugMode != 0)
        BEGIN
            PRINT @SQLUnion;
            PRINT @dbContext;
        END
    ELSE
        BEGIN
            -- Delete the temp table if it has already been created.
            IF OBJECT_ID ('tempdb..##ColumnsByValue') IS NOT NULL 
                BEGIN 
                    DROP TABLE ##ColumnsByValue 
                END

            -- Create a new temp table
            CREATE TABLE ##ColumnsByValue (
                K nvarchar(255), -- Key
                N nvarchar(255), -- Column Name
                V nvarchar(255)  -- Column Value
            )

            -- Populate it with the results from our dynamically generated SQL.
            INSERT INTO ##ColumnsByValue EXEC @dbContext @SQLUnion;
        END
END
GO

SP приема няколко входа като параметри, те са обяснени в следния код.

Имайте предвид също така, че предоставих механизъм за добавяне на „списък за игнориране“ като вход:

  • Това ви позволява да посочите имена на колони, които не трябва да бъдат включени в резултатите.
  • НЕ е необходимо да добавяте колоната, която използвате като ключ, т.е. row_id от вашата примерна структура.
  • ТРЯБВА да включите други колони, които не са varchar тъй като те ще причинят грешка (тъй като SP просто прави varchar сравнение на всички колони, които гледа).
  • Това се прави чрез временна таблица, която трябва да създадете/попълните
  • Вашата примерна структура на таблица предполага, че таблицата съдържа само колони, представляващи интерес, така че това може да не се отнася за вас.

Включих примерен код за това как да направите това (но направете това само ако имате нужда до):

IF OBJECT_ID ( 'tempdb..##GetColumnsByValueIgnoreList') IS NOT NULL
    BEGIN
        DROP TABLE ##GetColumnsByValueIgnoreList;
    END
CREATE TABLE ##GetColumnsByValueIgnoreList (column_name nvarchar(255));
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('a_column');
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('another_column');
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('yet_another_column');

Сега, за да задействате процедурата, която изгражда вашата временна таблица с резултати, използвайте следния код (и модифицирайте според случая, разбира се).

-- Build the ##ColumnsByValue table
EXEC dbo.GetColumnsByValue
    @idColumn = 'row_id',   -- The name of the column that contains your row ID (eg probably your PK column)
    @dbName = 'your_db_name',
    @tableName = 'your_table_name',
    @schemaName = 'dbo',
    @debugMode = 0          -- Set this to 1 if you just want a print out of the SQL used to build the temp table, to 0 if you want the temp table populated

Това ви оставя с ##ColumnsByValue , на който можете да извършите каквото ви е необходимо търсене, напр.:

select * from ##ColumnsByValue WHERE v = 'luxury' and k = 5 --some_row_id

Ще трябва да изпълните отново съхранената процедура (и ако е уместно, да създадете/промените таблицата със списъка за игнориране преди нея) за всяка таблица, която искате да прегледате.

Притеснение при този подход е, че дължината на nvarchar може да бъде превишена във вашия случай. Бихте вероятно. трябва да използвате различен тип данни, да намалите дължините на името на колоната и т.н. Или да го разделите на подстъпки и да обедините резултатите заедно, за да получите набора от резултати, който търсите.

Друго притеснение, което имам, е, че това е пълно преувеличение за вашия конкретен сценарий, при който еднократен прозорец от скрипт към заявка ще ви даде основата на това, от което се нуждаете, след което малко умно редактиране на текст в например Notepad++ ще ви осигури всичко натам... и следователно този проблем вероятно (и съвсем разумно) ще ви откаже да го правите по този начин! Но това е добър въпрос за общ случай и затова заслужава отговор за всеки, който се интересува в бъдеще;-)




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Какво е значението на SELECT ... FOR XML PATH(' ),1,1)?

  2. Как трябва да предам име на таблица в съхранена процедура?

  3. Има ли проблем с производителността при използване на ISNULL() в SQL Server?

  4. SQL - изберете отделни записи в едно поле с най-високи записи от друго поле

  5. Изходни параметри на съхранена процедура в SQL Server Profiler