【问题标题】:SQL: Return Column names where column contains a given ValueSQL:返回列名称,其中列包含给定值
【发布时间】:2013-12-05 16:26:41
【问题描述】:

我想知道是否有我可以在 SQL Server 中运行的命令/存储过程,它会给我包含表中给定数据的列的名称。

因此,如果我要查询,请给我此表中包含值 75 的所有列。我不想要该行。只是表中的列名......这可能吗?

【问题讨论】:

  • 这些都是字符串列吗?您是否需要动态的列名列表,或者您是否可以对它们进行硬编码?
  • 在某处似乎存在有缺陷的架构设计。但是您想知道表中是否有任何行具有该卷,或者您在执行此操作时是否会查看特定行?
  • 它需要是动态的,因为它需要在不同的数据库和表上运行。他们不会都是字符串列..我在这里问太多了吗?

标签: sql sql-server-2012


【解决方案1】:
-- input parameters (guessing on type for @value):

DECLARE 
  @schema SYSNAME = N'dbo', 
  @table  SYSNAME = N'z', 
  @value  VARCHAR(64) = '75';


-- now, inside the procedure body:

DECLARE @sql NVARCHAR(MAX) = N'SELECT ''cols:'' + STUFF(''''';

SELECT @sql += N' 
  + CASE WHEN EXISTS (SELECT 1 FROM ' 
  + QUOTENAME(@schema) + '.' + QUOTENAME(@table)
  + ' WHERE TRY_CONVERT(VARCHAR(64), ' + QUOTENAME(c.name) 
  + ') = @value) THEN '', ' + c.name + ''' ELSE '''' END'
FROM sys.tables AS t
INNER JOIN sys.columns AS c
ON t.[object_id] = c.[object_id]
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE t.name = @table AND s.name = @schema;

SET @sql += N', 1, 1, '''');'

PRINT @sql;

--EXEC sp_executesql @sql, N'@value VARCHAR(64)', @value;

当您对输出感到满意时,取消注释 EXEC。

让我们考虑一个简单的表格:

CREATE TABLE dbo.floob
(
  a INT, 
  b VARCHAR(32), 
  c VARBINARY(22), 
  d DATE, 
  e DATETIME, 
  f ROWVERSION
);

INSERT dbo.floob(a,b,c,d,e) VALUES
( 75, 'foo', 0x00, GETDATE(), GETDATE()),
( 21, '75',  0x00, GETDATE(), GETDATE());

现在,一个基于上述代码的存储过程:

CREATE PROCEDURE dbo.FindStringInAnyColumn
  @schema SYSNAME = N'dbo', 
  @table  SYSNAME,
  @value  VARCHAR(64)
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @sql NVARCHAR(MAX) = N'SELECT ''cols:'' + STUFF(''''';

  SELECT @sql += N' 
    + CASE WHEN EXISTS (SELECT 1 FROM ' 
    + QUOTENAME(@schema) + '.' + QUOTENAME(@table)
    + ' WHERE TRY_CONVERT(VARCHAR(64), ' + QUOTENAME(c.name) 
    + ') = @value) THEN '', ' + c.name + ''' ELSE '''' END'
  FROM sys.tables AS t
  INNER JOIN sys.columns AS c
  ON t.[object_id] = c.[object_id]
  INNER JOIN sys.schemas AS s
  ON t.[schema_id] = s.[schema_id]
  WHERE t.name = @table AND s.name = @schema;

  SET @sql += N', 1, 1, '''');'

  EXEC sp_executesql @sql, N'@value VARCHAR(64)', @value;
END
GO

示例用法:

EXEC dbo.FindStringInAnyColumn @table = N'floob', @value = '75';

输出:

Cols: a, b

【讨论】:

    【解决方案2】:

    我同意上述 cmets 的观点,听起来您的架构设计并不理想。如果您尝试在大型数据集上执行此操作,您可能会遇到性能问题。

    也就是说,您可以取消透视列以将它们转换为行。这是从 Technet 上的Using PIVOT and UNPIVOT 文章逐字提取的示例。我用的是 4 而不是 75:

    --Create the table and insert values as portrayed in the previous example.
    CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
        Emp3 int, Emp4 int, Emp5 int);
    GO
    INSERT INTO pvt VALUES (1,4,3,5,4,4);
    INSERT INTO pvt VALUES (2,4,1,5,5,5);
    INSERT INTO pvt VALUES (3,4,3,5,4,4);
    INSERT INTO pvt VALUES (4,4,2,5,5,4);
    INSERT INTO pvt VALUES (5,5,1,5,5,5);
    GO
    --Unpivot the table.
    SELECT VendorID, Employee, Orders
    FROM 
       (SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
       FROM pvt) p
    UNPIVOT
       (Orders FOR Employee IN 
          (Emp1, Emp2, Emp3, Emp4, Emp5)
    )AS unpvt
    WHERE VendorID = 1 AND orders = 4;
    

    这会产生以下结果:

    +---+----------------------------------------+ | | VendorID 员工订单 | +---+----------------------------------------+ | | 1 员工 1 4 | | | 1 员工 4 4 | | | 1 员工 5 4 | +---+----------------------------------------+

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 1970-01-01
      • 2020-08-30
      • 1970-01-01
      • 2020-02-02
      • 1970-01-01
      • 2018-01-03
      相关资源
      最近更新 更多