sql >> データベース >  >> RDS >> Sqlserver

SQL Server-特定の条件を満たす列を選択しますか?

    ストアドプロシージャを作成しました。

    このプロシージャは、MSSQLメタを調べて、列名Nを含む結果を返す動的SQL文字列を作成します。 およびそれらの値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を実行するため) 表示されるすべての列の比較)。
    • これは、作成/入力する必要のある一時テーブルを介して行われます
    • テーブル構造の例では、テーブルに対象の列のみが含まれていることを示しているため、これは当てはまらない可能性があります。

    これを行う方法のサンプルコードを含めました(ただし、必要な場合にのみこれを行ってください) to):

    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の長さが超過する可能性があることです。あなたはたぶんだろう。異なるデータ型を使用したり、列名の長さを短くしたりする必要があります。または、サブステップに分割し、結果を結合して、目的の結果セットを取得します。

    私が持っているもう1つの懸念は、これが特定のシナリオでは完全にやり過ぎであるということです。このシナリオでは、1回限りのscript-to-query-windowが必要なものの基礎を提供し、Notepad++などの巧妙なテキスト編集ですべてが得られます。そこに行く方法...したがって、この問題はおそらく(そしてかなり合理的に)あなたがこの方法でそれをするのを延期するでしょう!しかし、これは一般的な質問として適切であるため、将来に関心のある人には答える価値があります;-)




    1. SQLサーバーは日時を別のタイムゾーンに変換しますか?

    2. 単一のクエリでwhereフィルターを使用して30kのMySQLテーブルから3つのランダムレコードをすばやく選択するにはどうすればよいですか?

    3. ローカルホスト(xampp)でMySQLの厳密モードをオン/オフにする方法は?

    4. 非常に大きなテーブルでの(列ストア)圧縮の楽しみ–パート2