sql >> Database >  >> RDS >> Sqlserver

SQL Server - Kolommen selecteren die aan bepaalde voorwaarden voldoen?

Ik heb een opgeslagen procedure voor je gemaakt.

Deze procedure onderzoekt de MSSQL-meta om een ​​dynamische SQL-tekenreeks te bouwen die een resultaat retourneert met kolomnamen N en hun waarden V , en de bijbehorende rijsleutel K waaruit die waarde is opgehaald, voor een opgegeven tabel.

Wanneer dit wordt uitgevoerd, worden de resultaten opgeslagen in een globale tijdelijke tabel met de naam ##ColumnsByValue, die vervolgens direct kan worden opgevraagd.

Maak de GetColumnsByValue opgeslagen procedure, door dit script uit te voeren:

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

De SP neemt verschillende ingangen als parameters, deze worden uitgelegd in de volgende code.

Merk ook op dat ik een mechanisme heb geleverd om een ​​"negerenlijst" als invoer toe te voegen:

  • Hiermee kunt u alle kolomnamen weergeven die niet in de resultaten mogen worden opgenomen.
  • U hoeft NIET de kolom toe te voegen die u als uw sleutel gebruikt, dwz de row_id van uw voorbeeldstructuur.
  • U MOET andere kolommen opnemen die niet varchar zijn aangezien deze een fout veroorzaken (omdat de SP gewoon een varchar doet) vergelijking op alle kolommen waar het naar kijkt).
  • Dit wordt gedaan via een tijdelijke tabel die u moet maken/invullen
  • Uw voorbeeldtabelstructuur suggereert dat de tabel alleen interessante kolommen bevat, dus dit is mogelijk niet op u van toepassing.

Ik heb voorbeeldcode toegevoegd om dit te doen (maar doe dit alleen als u nodig naar):

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

Om nu de procedure te starten die uw tijdelijke resultatentabel maakt, gebruikt u de volgende code (en past u deze natuurlijk aan waar nodig).

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

Dit geeft je ##ColumnsByValue , waarop u elke zoekopdracht kunt uitvoeren die u nodig heeft, bijvoorbeeld:

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

U moet de opgeslagen procedure opnieuw uitvoeren (en, indien relevant, de negeerlijsttabel ervoor maken/wijzigen) voor elke tabel die u wilt onderzoeken.

Een punt van zorg bij deze aanpak is dat de nvarchar-lengte in uw geval kan worden overschreden. Je zou waarschijnlijk. moet een ander gegevenstype gebruiken, de lengte van de kolomnaam verkleinen, enz. Of verdeel het in substappen en voeg de resultaten samen om de gewenste resultatenset te krijgen.

Een andere zorg die ik heb, is dat dit complete overkill is voor jouw specifieke scenario, waar een eenmalig script-naar-query-venster je de basis zal geven van wat je nodig hebt, en dan zal een slimme tekstbewerking in bijvoorbeeld Notepad ++ je alle en daarom zal dit probleem je er waarschijnlijk (en redelijkerwijs) van weerhouden om het op deze manier te doen! Maar het is een goede algemene vraag, en verdient dus een antwoord voor iedereen die geïnteresseerd is in de toekomst;-)




  1. 'LIKE ('%this%' OR '%that%') en iets=anders' werkt niet

  2. De string splitsen in de sql-server

  3. Fout gerelateerd aan only_full_group_by bij het uitvoeren van een query in MySql

  4. Selecteer record(s) uit mysql-tabel waarvan de datum groter is dan of gelijk is aan vandaag