sql >> Databáze >  >> RDS >> Sqlserver

SQL Server – vybrat sloupce, které splňují určité podmínky?

Vytvořil jsem pro vás uloženou proceduru.

Tento postup zkoumá meta MSSQL a vytváří dynamický řetězec SQL, který vrací výsledek obsahující názvy sloupců N a jejich hodnoty V a odpovídající klíč řádku K ze kterého byla tato hodnota načtena, pro zadanou tabulku.

Když se to provede, výsledky se uloží do globální dočasné tabulky s názvem ##ColumnsByValue, na kterou lze poté přímo dotazovat.

Vytvořte GetColumnsByValue uloženou proceduru, spuštěním tohoto skriptu:

-- =============================================
-- 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 má několik vstupů jako parametry, ty jsou vysvětleny v následujícím kódu.

Všimněte si také, že jsem poskytl mechanismus pro přidání "seznamu ignorovaných" jako vstupu:

  • To vám umožní uvést názvy sloupců, které by neměly být zahrnuty ve výsledcích.
  • NEPOTREBUJETE přidávat sloupec, který používáte jako klíč, tj. row_id z vaší vzorové struktury.
  • MUSÍTE zahrnout další sloupce, které nejsou varchar protože tyto způsobí chybu (jako SP právě provede varchar porovnání všech sloupců, na které se dívá).
  • To se provádí pomocí dočasné tabulky, kterou musíte vytvořit/naplnit
  • Vaše ukázková struktura tabulky naznačuje, že tabulka obsahuje pouze sloupce, které vás zajímají, takže se vás to nemusí týkat.

Zahrnul jsem příklad kódu, jak to udělat (ale udělejte to pouze v případě, že potřebujete komu):

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');

Chcete-li nyní spustit proceduru, která vytváří vaši dočasnou tabulku výsledků, použijte následující kód (a podle potřeby jej samozřejmě upravte).

-- 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

Získáte tak ##ColumnsByValue , na kterém můžete provádět jakékoli vyhledávání, např.:

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

Budete muset znovu spustit uloženou proceduru (a pokud je to relevantní, vytvořit/upravit tabulku seznamu ignorovaných před ní) pro každou tabulku, kterou chcete prozkoumat.

Problém s tímto přístupem je, že ve vašem případě může dojít k překročení délky nvarchar. Hádal bys. potřebujete použít jiný datový typ, zmenšit délku názvů sloupců atd. Nebo to rozdělit do dílčích kroků a sjednotit výsledky dohromady, abyste získali výslednou sadu, kterou hledáte.

Další obava, kterou mám, je, že je to pro váš konkrétní scénář naprostý přehnaný, kde vám jednorázový skript-do-okno dotazu dá základ toho, co potřebujete, a pak nějaká chytrá úprava textu např. v Notepad++ vám vše poskytne tam... a proto vás tento problém pravděpodobně (a docela rozumně) odradí od toho, abyste to dělali tímto způsobem! Ale je to dobrá obecná otázka, a tak si zaslouží odpověď pro každého, koho zajímá budoucnost;-)




  1. Jak se připojit k databázi MySQL?

  2. Deklarujte proměnnou složeného typu v PostgreSQL pomocí %TYPE

  3. Jak vynásobit dvě hodnoty sloupce a zobrazit jeho výsledek na konci každého řádku?

  4. Odeberte opakující se data ve sloupci