SQL: Return Column names where column contains a given Value

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-01 14:28:54
-- 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;

When you are happy with the output, uncomment the EXEC.

So let's consider a simple table:

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());

Now, a stored procedure based on the above code:

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

Sample usage:

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

Output:

Cols: a, b

I agree with the above comments that it sounds like you have a suboptimal schema design. You will probably run into performance issues if you try to do this on a large data set.

That said, you could unpivot the columns to convert them to rows. Here is an example lifted verbatim from the Using PIVOT and UNPIVOT article on Technet. Instead of 75, I used 4:

--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;

This yields the following result:

+--+----------------------------------------+
|  | VendorID        Employee        Orders |
+--+----------------------------------------+
|  | 1               Emp1            4      |
|  | 1               Emp4            4      |
|  | 1               Emp5            4      |
+--+----------------------------------------+
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!