繁体   English   中英

需要一行中的所有列

[英]Need all columns on one row

我写了以下查询:

IF OBJECT_ID ('tempdb..#ColumnsType') IS NOT NULL DROP TABLE #ColumnsType
DECLARE @vQuery NVARCHAR(MAX) =''

IF OBJECT_ID ('tempdb..#random') IS NOT NULL DROP TABLE #random

CREATE TABLE #random (
ColumnID INT PRIMARY KEY IDENTITY(1,1) NOT NULL
, randomname VARCHAR(50)
, randomvalue INT)


INSERT INTO #random (randomname, randomvalue)
VALUES ('a3', 123)
    , ('bla', 4325)
    , ('another_bla', 5643)
    , ('end_here', 3)

select *
from #random

CREATE TABLE #ColumnsType (
                ColumnID INT PRIMARY KEY IDENTITY(1,1) NOT NULL
                , ColumnName sysname 
                , DataType sysname
                )

 
INSERT INTO #ColumnsType (ColumnName, DataType)
SELECT [name],
        system_type_id    
FROM Tempdb.Sys.Columns
WHERE Object_ID = Object_ID('tempdb..#random')
AND system_type_id = 56



DECLARE @i INT = (SELECT MIN(ColumnID) FROM #random);
DECLARE @maxId INT = (SELECT MAX(ColumnID) FROM #random);
DECLARE @ColumnName VARCHAR(200);
DECLARE @DataType VARCHAR(200);

WHILE @i <= @maxId
BEGIN
    SET @ColumnName = (SELECT ColumnName FROM #ColumnsType WHERE ColumnId = @i)

    -- SET @DataType = (SELECT DataType FROM #ColumnsType WHERE ColumnId = @i)

    SELECT @vQuery =
    'SELECT 

            MIN(TRY_CONVERT(NUMERIC(30, 4), ' +@ColumnName+ ')) AS ' +@ColumnName+ '_MinValue
            , MAX(TRY_CONVERT(NUMERIC(30, 4), ' +@ColumnName+ ')) AS ' +@ColumnName+ '_MaxValue
            , AVG(TRY_CONVERT(NUMERIC(30, 4), ' +@ColumnName+ ')) AS ' +@ColumnName + '_AvgValue
            , STDEV(TRY_CONVERT(NUMERIC(30, 4), ' +@ColumnName+ ')) AS ' +@ColumnName+ '_StandardDeviation
            , SUM(TRY_CONVERT(NUMERIC(30, 4), ' +@ColumnName+  ')) AS ' +@ColumnName+ '_TotalSum      
    FROM tempdb..#random'   -- +@Schema+'.'+@Table+ ''

    EXEC sp_executesql @vQuery
    PRINT @vQuery

    SET @i = @i + 1
END

为了演示,我创建了具有随机值的临时表。 我对仅由数值组成的部分列执行分析。 要过滤列,我使用Tempdb.Sys.Columns获取它们的名称并按类型过滤。 在我的原始数据的正常情况下,我使用INFORMATION_SCHEMA.COLUMNS但我认为这并不重要。

查询返回以下内容:

在此处输入图像描述

结果显示在两行中。 我想做的是将这个结果排成一行。 这个想法是 pivot 之后的一行结果,并收到以下结果:

在此处输入图像描述

正如我提到的,您不需要使用循环,而是使用基于集合的方法和UNION ALL动态语句。 我在这里也假设您使用的是最新版本的 SQL 服务器。 如果没有,您需要将STRING_AGG替换为旧的FOR XML PATH (和STUFF )方法。

这应该足以让你开始:

USE Sandbox;
GO

CREATE TABLE dbo.YourTable (Col1 int,
                            Col2 varchar(10));
GO

DECLARE @SchemaName sysname = N'dbo',
        @TableName sysname = N'YourTable';

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

DECLARE @Delimiter nvarchar(50) = @CRLF + N'UNION ALL' + @CRLF;
        
SELECT @SQL = STRING_AGG(CONVERT(nvarchar(MAX),N'SELECT MIN(') + QUOTENAME(c.[name]) + N') AS ' + QUOTENAME(c.[name] + N'_MIN') + N',' + @CRLF +
                         N'       MAX(' + QUOTENAME(c.[name]) + N') AS ' + QUOTENAME(c.[name] + N'_MAX') + @CRLF + 
                         N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name])
                         ,@Delimiter) WITHIN GROUP (ORDER BY c.column_id)
FROM sys.schemas s
     JOIN sys.tables t ON s.schema_id = t.schema_id
     JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.[name] = @SchemaName
 AND t.[name] = @TableName

PRINT @SQL;

EXEC sys.sp_executesql @SQL;
GO

DROP TABLE dbo.YourTable;

这是一个非常干净和漂亮的解决方案,这正是我一直在寻找的:

  • 我从特定表中选择列,扫描一次并对其执行多次计算
  • 我使用动态查询并将其作为所有列的一条语句。
  • 它工作得非常快。 返回包含 5000 万行的表的结果用了 5 分钟多一点。

剩下要做的唯一一件事就是 UNPIVOT,以便将结果插入我想要的表中。

    DECLARE
    @q1 NVARCHAR(MAX)
,   @q2 NVARCHAR(MAX)
,   @q3 NVARCHAR(500)
,   @schema VARCHAR(50) = '' -- choose schema
,   @table VARCHAR(200) = '' -- choose table

SET @Q1 = 'SELECT ' + '''' + @table + '''' + ' as tableName, '
SET @Q3 = ' FROM ' + @schema + '.' + @table
SELECT @q2 = COALESCE(@q2 + ', ', '') 
+ ' max(' + columnName + ') as ' + columnName + '_max, ' 
+ ' min(' + columnName + ') as ' + columnName + '_min, '
+ ' avg(' + columnName + ') as ' + columnName + '_avg, '
+ ' stdev(' + columnName + ') as ' + columnName + '_stdev, '
+ ' sum(' + columnName + ') as ' + columnName + '_sum '
FROM (
SELECT s.[name] as schemaName, t.[name] as tableName, c.[name] as columnName, st.[name] as typeName 
FROM sys.schemas s
    INNER JOIN sys.tables t ON s.schema_id = t.schema_id
    INNER JOIN sys.columns c ON t.object_id = c.object_id
    INNER JOIN sys.types st ON st.user_type_id = c.user_type_id
WHERE 1=1
AND s.[name] = @schema
AND t.[name] = @table
AND st.[name] IN ('') -- choose columns of specific data type, that you want to profile
 ) data

SELECT @q1 = @q1 + @q2 + @q3

EXEC sys.sp_executesql @Q1 

享受!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM