2013-12-05 5 views
0

Мне было интересно, есть ли команда/хранимая proc, которую я могу запустить в SQL Server, которая даст мне имена столбцов, содержащих данные в таблице.SQL: вернуть имена столбцов, где столбец содержит заданное значение

Так что если бы я был запрошен, дайте мне все столбцы в этой таблице, которые содержат значение 75. Я бы не хотел строку. просто имя столбца в таблице ... возможно ли это?

+0

эти все столбцы со строками? Вам нужен список имен столбцов, чтобы быть динамичным, или вы в порядке с жестким кодированием? –

+0

Кажется, что там где-то есть недостаток схемы. Но вы хотите знать, имеет ли какая-либо строка в таблице этот том или вы будете смотреть на определенную строку, когда вы это сделаете? –

+0

, он должен быть динамическим, поскольку его нужно будет запускать в разных базах данных и таблицах. и они бы не были строковыми колонками .. я слишком много спрашиваю здесь? – osmo

ответ

2
-- 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 
+0

Это был мой подход, но вы быстрее, хорошо сделали – Koryu

+0

большое спасибо за это! – osmo

0

Я согласен с приведенными выше комментариями, что это звучит так, будто у вас есть субоптимальный дизайн схемы. Вероятно, вы столкнетесь с проблемами производительности, если попытаетесь сделать это на большом наборе данных.

Это означает, что вы можете отключить столбцы, чтобы преобразовать их в строки. Вот пример, поднятый дословно из статьи Using PIVOT and UNPIVOT о Technet. Вместо 75, я использовал 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; 

Это приводит к следующему результату:

 
+--+----------------------------------------+ 
| | VendorID  Employee  Orders | 
+--+----------------------------------------+ 
| | 1    Emp1   4  | 
| | 1    Emp4   4  | 
| | 1    Emp5   4  | 
+--+----------------------------------------+ 
Смежные вопросы