问题
I have seen multiple questions on how to retrieve every column from every table along with its data type, among many other pieces of information which can be summarised in the shortest way with this query:
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
However, is it possible to get all the data from the columns and the rows they belong to get the first row in the table alongside this? I have not found a way to do so thus far. Is it possible to do such, maybe also having a WHERE
condition such as checking if the table contains a list of specific columns before returning it e.g.:
SELECT <AllTablesAndColumns+FirstRow>
FROM <WhereTheyCanBeSelectedFrom>
WHERE <TheTableHasTheseSpecificColumns>
Which would return the table name, column name and the data contained within those columns for each row.
回答1:
You could build dynamic query:
DECLARE @sql NVARCHAR(MAX) =
N'SELECT *
FROM (VALUES (1)) AS s(n)
<joins>';
DECLARE @joins NVARCHAR(MAX)= '';
SELECT @joins += FORMATMESSAGE('LEFT JOIN (SELECT TOP 1 * FROM %s ) AS sub%s
ON 1=1' + CHAR(10), table_schema + '.' + table_name,
CAST(ROW_NUMBER() OVER(ORDER BY 1/0) AS VARCHAR(10)))
FROM (SELECT DISTINCT table_schema, table_name
FROM INFORMATION_SCHEMA.COLUMNS
-- WHERE ... -- custom logic based on column type/name/...
) s;
SET @sql = REPLACE(@sql, '<joins>', @joins);
PRINT @sql;
EXEC(@sql);
DBFiddle Demo
The dynamic query has structure:
SELECT *
FROM (VALUES (1)) AS s(n) -- always 1 row
LEFT JOIN (SELECT TOP 1 * FROM dbo.tab1 ) AS sub1 ON 1=1 -- get single row
LEFT JOIN (SELECT TOP 1 * FROM dbo.tab2 ) AS sub2 ON 1=1
LEFT JOIN (SELECT TOP 1 * FROM dbo.tabC ) AS sub3 ON 1=1
Please treat it as starting point. You could easily extend it with WHERE
condition for each subquery and return specific columns instead of *.
EDIT:
Version with UNION ALL
:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = COALESCE(@sql + ' UNION ALL', '') +
FORMATMESSAGE(' SELECT TOP 1 tab_name=''%s'',col_name=''%s'',col_val=%s FROM %s'+CHAR(10)
,table_name, column_name, column_name, table_schema + '.' + table_name)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE column_name LIKE 'colV%';
PRINT @sql;
EXEC(@sql);
DBFiddle Demo2
回答2:
If you are looking for more of an EAV structure
Let's say that we're looking for all tables with a column name of ZIPCODE
Example
Declare @S varchar(max) = ''
SELECT @S = @S +'+(Select top 1 SourceTable='''+A.Table_Name+''',* from '+quotename(A.Table_Name)+' for XML RAW)'
FROM INFORMATION_SCHEMA.COLUMNS A
Where COLUMN_NAME in ('ZipCode')
Declare @SQL varchar(max) = '
Declare @XML xml = '+stuff(@S,1,1,'')+'
Select SourceTable = r.value(''@SourceTable'',''varchar(100)'')
,Item = attr.value(''local-name(.)'',''varchar(100)'')
,Value = attr.value(''.'',''varchar(max)'')
From @XML.nodes(''/row'') as A(r)
Cross Apply A.r.nodes(''./@*'') AS B(attr)
Where attr.value(''local-name(.)'',''varchar(100)'') not in (''SourceTable'')
'
Exec(@SQL)
Returns
来源:https://stackoverflow.com/questions/52246897/get-data-from-every-column-in-every-table-in-a-database-sql-server