2013-03-21 50 views
2

我的COLUMNS只能包含三個值或var chars - 經濟,基本,奢華。我想選擇一個行,並只顯示那些包含奢侈品的列。問題是有很多這樣的列 - 大約50個。我不想在我的選擇查詢中鍵入所有這些列的名稱。有沒有更簡單的替代方案?我應該使用哪個查詢?SQL Server - 選擇符合特定條件的列?

我想到的是這樣的(這是假的查詢) -

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

表結構 -

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

是的,我已經看到這種情況使用元從系統表,我敢肯定有人比我更會knowleagable根據這些方面提供答案。但同時,請嘗試右鍵單擊表>腳本表爲>創建到>新查詢編輯器窗口?腳本中給出了整個列的列表。根據需要複製並使用這些字段。 (從http://stackoverflow.com/questions/600446/sql-server-how-do-you-return-the-column-names-from-a-table) – Sepster 2013-03-21 03:39:08

+0

由於沒有一個已加強了一個間位基於計算機的答案...我已經添加了一個在我的小測試數據庫下工作的。 – Sepster 2013-03-21 04:29:28

回答

2

我創建了一個存儲過程你。

此過程檢查MSSQL元構建返回包含列名N和它們的值V結果的動態SQL字符串,相應的行鍵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比較 )。
  • 這是通過你必須創建/填充
  • 你的示例表結構表明 表中包含的興趣只列一個臨時表完成的,所以這可能並不適用於 你。

,我們提供瞭如何做到這一點(但只有這樣做,如果你需要)示例代碼:

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表名'。查詢成功執行,但沒有發生任何事情。 – 2013-03-21 06:56:00

+0

您的查詢是否對我的表進行了任何永久更改?或者它只是暫時的? – 2013-03-21 06:56:26

+0

代碼運行並返回您提到的結果。我如何在select語句中使用你的代碼。我試着運行SELECT Column_Name WHERE Column_Value ='luxury';在這個查詢後出現錯誤。 – 2013-03-21 07:44:36