2

私の COLUMNS には、エコノミー、ベーシック、ラグジュアリーの 3 つの値または変数文字のみを含めることができます。行を選択し、贅沢を含む列のみを表示したいと考えています。問題は、そのような列がたくさんあることです - 約 50 です。select クエリにこれらすべての列の名前を入力したくありません。これに代わる短くて簡単な代替手段はありますか? どのクエリを使用すればよいですか?

私はこのようなことを考えています(これは偽のクエリです)-

@declare Column_Name varchar(30)
select Column_Name where Column_Value = 'luxury' 
from ATable
where rowId = 'row 5';

テーブル構造 -

rowId | Column1 | Column2 | Column3.....
4

1 に答える 1

2

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

Nこのプロシージャは、MSSQL メタを調べて、指定されたテーブルの列名とその値、およびその値が取得されVた対応する行キーを含む結果を返す動的 SQL 文字列を作成します。K

これが実行されると、結果は ##ColumnsByValue と呼ばれるグローバル一時テーブルに格納され、直接クエリを実行できます。

GetColumnsByValue次のスクリプトを実行して、ストアド プロシージャを作成します。

-- =============================================
-- Author:      Ben Roberts (sepster@internode.on.net)
-- 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 '+@idColumn+' as K, '''+@colName+''' as N, ' +@colName+ ' 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 の長さが超過する可能性があることです。あなたはおそらくでしょう。異なるデータ型を使用したり、列名の長さを短くしたりする必要があります。または、サブステップに分割し、結果を結合して、目的の結果セットを取得します。

私が持っているもう1つの懸念は、これが特定のシナリオでは完全にやり過ぎであることです.1回限りのスクリプトからクエリウィンドウへのスクリプトが必要なものの基礎を提供し、たとえばNotepad ++での巧妙なテキスト編集がすべてを取得します.そこまで...したがって、この問題はおそらく(そしてかなり合理的に)この方法で行うことを先延ばしにします!しかし、これは一般的な質問であり、将来に関心のある人にとっては回答に値するものです ;-)

于 2013-03-21T04:24:09.533 に答える