2013-03-21 2 views
2

Мои COLUMNS могут содержать только три значения или var chars - экономичный, простой, роскошный. Я хочу выбрать ROW и отображать только те COLUMNS, которые содержат роскошь. Проблема в том, что таких столбцов много - около 50. Я не хочу набирать имена всех этих столбцов в моем запросе выбора. Существует ли более короткая и простая альтернатива этому? Какой запрос я должен использовать?SQL Server - выберите столбцы, соответствующие определенным условиям?

Я имею в виду что-то вроде этого (это FAKE запрос) -

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

Таблица структура -

rowId | Column1 | Column2 | Column3..... 
+1

Да, я видел это, используя meta из системных таблиц, и я уверен, что кто-то более узнаваемый, чем я, будет дать ответ в этом направлении. Но в то же время попробуйте щелкнуть правой кнопкой мыши по таблице> Таблица сценариев как> Создать в> Новое окно редактора запросов? Весь список столбцов указан в скрипте. Скопируйте его и используйте поля по мере необходимости. (из http://stackoverflow.com/questions/600446/sql-server-how-do-you-return-the-column-names-from-a-table) – Sepster

+0

Поскольку никто не активизировал мета- основанный на ответе ... Я добавил один ниже, который работал для меня на небольшом тестовом db. – Sepster

ответ

2

Я создал хранимую процедуру для вас.

Эта процедура проверяет мету 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 

СП имеет несколько входов в качестве параметров, они описаны в следующем коде.

Отметим также, что я предоставил механизм для добавления «список игнорирования» в качестве входного сигнала:

  • Это позволяет перечислить все имена столбцов, которые не должны быть включены в результатах.
  • Вам не нужно добавлять столбец n, который вы используете в качестве ключа, то есть 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 ++, будет добирайся до конца ... и, следовательно, эта проблема, скорее всего, (и вполне разумно) заставит тебя так поступать! Но это хороший общий вопрос, и поэтому заслуживает ответа для всех, кто интересуется будущим ;-)

+0

Sepster - Я попробовал ваш запрос. Не уверен, что я сделал это правильно. Я установил @dbName = 'мое имя базы данных', schemaName = 'dbo' и tName = 'dbo.My имя таблицы'. Запрос выполнен успешно, но ничего не произошло. –

+0

делает ли ваш запрос какие-либо постоянные изменения в моей таблице или это временно? –

+0

Код запускается и возвращает результат, который вы упомянули. Как использовать этот код внутри оператора select. Я попытался запустить SELECT Column_Name WHERE Column_Value = 'luxury'; после этого запроса и получил ошибку. –

Смежные вопросы