【问题标题】:Select columns from another select as rows for each column从另一个选择中选择列作为每列的行
【发布时间】:2013-07-26 18:48:23
【问题描述】:

好的,我知道这可能难以理解,请随时对其进行编辑,使其更有意义。基本上我想旋转我的结果。我想从 (select col1, col2 from table) tmp_table 中选择 *,但是将 tmp_table 结果中的所有列都作为行。下面是选择 tmp_table:

select
txt_description_1   label_1,
txt_description_2   label_2,
txt_description_3   label_3,
txt_description_4   label_4,
txt_description_5   label_5,
txt_description_6   label_6,
txt_description_7   label_7,
txt_description_8   label_8,
txt_description_9   label_9,
txt_description_10  label_10,
txt_description_11  label_11,
txt_description_12  label_12,
txt_description_13  label_13,
txt_description_14  label_14,
txt_description_15  label_15,
txt_description_16  label_16,
txt_description_17  label_17,
txt_description_18  label_18,
txt_description_19  label_19,
txt_description_20  label_20,
txt_description_21  label_21,
txt_description_22  label_22,
txt_description_23  label_23,
txt_description_24  label_24,
txt_description_25  label_25,
txt_description_26  label_26,
txt_description_27  label_27,
txt_description_28  label_28,
txt_description_29  label_29,
txt_description_30  label_30,
txt_description_31  label_31,
txt_description_32  label_32,
txt_description_33  label_33,
txt_description_34  label_34,
txt_description_35  label_35,
txt_description_36  label_36,
txt_description_37  label_37,
txt_description_38  label_38,
txt_description_39  label_39,
txt_description_40  label_40,
txt_description_41  label_41,
txt_description_42  label_42,
txt_description_43  label_43,
txt_description_44  label_44,
txt_description_45  label_45,
txt_description_46  label_46,
txt_description_47  label_47,
txt_description_48  label_48,
txt_description_49  label_49,
txt_description_50  label_50,
txt_description_51  label_51,
txt_description_52  label_52,
txt_description_53  label_53,
txt_description_54  label_54,
txt_description_55  label_55,
txt_description_56  label_56,
txt_description_57  label_57,
txt_description_58  label_58,
txt_description_59  label_59,
txt_description_60  label_60,
txt_info2   label_info2
from ngkbm_template_data_sets_
where practice_id = '0001'
and txt_data_set = @dataSet
and chk_label_values = 1

假设输出如下所示:

Protocol    Test    Dx Code Dx  Test Code   Interval    Start Age   Stop Age    Gender  NULL    NULL    Test Code (Medicare)    Test Code (Medicare, Hish Risk) Interval (High Risk)    Start Age (High Risk)   Stop Age (High Risk)    NULL    NULL    Seq # for Series    Pre-Requisite Exam  Pre-Requisite Exam Seq #    Class   NULL    Other ID    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    Set Info / Reference:

我想让它显示如下:

Protocol
Test
Dx Code
Dx
Test Code
INTERVAL
Start Age
Stop Age
Gender
NULL
NULL

我也在为 SSRS 2005 这样做,所以这些限制适用。此外,选择只会返回一行,因此处理多行不是问题。

【问题讨论】:

    标签: sql-server sql-server-2005 reportingservices-2005


    【解决方案1】:

    你可以使用CROSS APPLY:

    DECLARE @ngkbm_template_data_sets_ TABLE(
        id                  INT IDENTITY(1,1) PRIMARY KEY,
        txt_description_1   VARCHAR(50) NULL, -- or NVARCHAR,etc.
        txt_description_2   VARCHAR(50) NULL,
        txt_description_3   VARCHAR(50) NULL,
        txt_description_4   VARCHAR(50) NULL
    );
    
    INSERT  @ngkbm_template_data_sets_(txt_description_1,txt_description_2,txt_description_3,txt_description_4)
    VALUES  ('Protocol','Test','Dx',NULL);
    
    SELECT  x.id,y.*
    FROM    @ngkbm_template_data_sets_ x
    CROSS APPLY(
        SELECT  x.txt_description_1 AS Value, 'txt_description_1' AS ColumnName
        UNION ALL
        SELECT  x.txt_description_2 AS Value, 'txt_description_2' AS ColumnName
        UNION ALL
        SELECT  x.txt_description_3 AS Value, 'txt_description_3' AS ColumnName
        UNION ALL
        SELECT  x.txt_description_4 AS Value, 'txt_description_4' AS ColumnName         
    )y;
    

    结果:

    id Value    ColumnName
    -- -------- -----------------
    1  Protocol txt_description_1
    1  Test     txt_description_2
    1  Dx       txt_description_3
    1  NULL     txt_description_4
    

    编辑 1:以下测试中,从CPU timeelapsed time 的角度来看,两种解决方案(CROSS APPLY + UNION ALLUNION ALL only)的性能相当

    CPU time = 156 ms,  elapsed time = 2452 ms.
    vs.
    CPU time = 172 ms,  elapsed time = 2344 ms.
    

    但从LIO(logical reads) 的角度来看,结果显示出巨大的差异:

    Table 'SalesOrderHeader'. Scan count 1, logical reads 686
    vs.
    Table 'SalesOrderHeader'. Scan count 6, logical reads 2881.
    

    每个解决方案的实际执行计划都显示了造成这种差异的原因: CROSS APPLY + UNION ALL 解决方案仅使用一个Clustered Index Scan,但UNION ALL only 解决方案使用四个Clustered Index Scan 运算符和两个Index Scan 运算符。此外,每个查询的估计总成本表明 SQL Server“认为”CROSS APPLY + UNION ALL (39%) 解决方案比UNION ALL only (61%) 稍好一点。对于这个测试,我使用了AdventureWorks2008 R2 database

    SET NOCOUNT ON;
    SET STATISTICS IO,TIME ON;
    GO
    PRINT 'CROSS APPLY';
    SELECT  h.SalesOrderID,x.*
    FROM    Sales.SalesOrderHeader h
    CROSS APPLY(
        SELECT h.SalesOrderNumber AS Value, 'SalesOrderNumber' AS RowType
        UNION ALL
        SELECT h.PurchaseOrderNumber, 'PurchaseOrderNumber'
        UNION ALL
        SELECT h.AccountNumber , 'AccountNumber'
        UNION ALL
        SELECT h.CreditCardApprovalCode , 'CreditCardApprovalCode'
        UNION ALL
        SELECT h.Comment , 'Comment'    
        UNION ALL
        SELECT CONVERT(VARCHAR(36),h.rowguid) , 'rowguid'
    )x
    GO
    PRINT 'UNION ALL only';
    SELECT h.SalesOrderID,h.SalesOrderNumber AS Value, 'SalesOrderNumber' AS RowType FROM   Sales.SalesOrderHeader h
    UNION ALL
    SELECT h.SalesOrderID,h.PurchaseOrderNumber, 'PurchaseOrderNumber' FROM Sales.SalesOrderHeader h
    UNION ALL
    SELECT h.SalesOrderID,h.AccountNumber , 'AccountNumber' FROM    Sales.SalesOrderHeader h
    UNION ALL
    SELECT h.SalesOrderID,h.CreditCardApprovalCode , 'CreditCardApprovalCode' FROM  Sales.SalesOrderHeader h
    UNION ALL
    SELECT h.SalesOrderID,h.Comment , 'Comment' FROM    Sales.SalesOrderHeader h    
    UNION ALL
    SELECT h.SalesOrderID,CONVERT(VARCHAR(36),h.rowguid) , 'rowguid' FROM   Sales.SalesOrderHeader h
    GO
    
    SET NOCOUNT OFF;
    SET STATISTICS IO,TIME OFF;
    GO
    /*
    -- Output
    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 0 ms.
    
    CROSS APPLY + UNION ALL
    
     SQL Server Execution Times:
       CPU time = 0 ms,  elapsed time = 0 ms.
    Table 'SalesOrderHeader'. Scan count 1, logical reads 686, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    
     SQL Server Execution Times:
       CPU time = 156 ms,  elapsed time = 2452 ms.
    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 0 ms.
    
    UNION ALL only
    
     SQL Server Execution Times:
       CPU time = 0 ms,  elapsed time = 0 ms.
    Table 'SalesOrderHeader'. Scan count 6, logical reads 2881, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    
     SQL Server Execution Times:
       CPU time = 172 ms,  elapsed time = 2344 ms.
    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 0 ms.
    
     SQL Server Execution Times:
       CPU time = 0 ms,  elapsed time = 0 ms.
    */
    

    【讨论】:

    • 哇,这让我觉得有点愚蠢。我一直在寻找这种过于复杂或超级优雅的解决方案,但像往常一样,我只是让它变得比需要的更难。
    • 现在我明白了。我更改了查询以获得您说明的性能提升。
    【解决方案2】:

    我真的不需要 Bogdan Sahlean 建议的 APPLY。而是简单地将一堆选择结合在一起,然后从中选择,消除了创建表变量或类似的东西的需要......

    SELECT name FROM (
    SELECT 1 id, txt_description_1 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 2 id, txt_description_2 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 3 id, txt_description_3 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 4 id, txt_description_4 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 5 id, txt_description_5 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 6 id, txt_description_6 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 7 id, txt_description_7 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 8 id, txt_description_8 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 9 id, txt_description_9 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 10 id, txt_description_10 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 11 id, txt_description_11 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 12 id, txt_description_12 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 13 id, txt_description_13 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 14 id, txt_description_14 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 15 id, txt_description_15 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 16 id, txt_description_16 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 17 id, txt_description_17 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 18 id, txt_description_18 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 19 id, txt_description_19 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 20 id, txt_description_20 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 21 id, txt_description_21 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 22 id, txt_description_22 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 23 id, txt_description_23 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 24 id, txt_description_24 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 25 id, txt_description_25 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 26 id, txt_description_26 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 27 id, txt_description_27 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 28 id, txt_description_28 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 29 id, txt_description_29 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 30 id, txt_description_30 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 31 id, txt_description_31 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 32 id, txt_description_32 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 33 id, txt_description_33 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 34 id, txt_description_34 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 35 id, txt_description_35 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 36 id, txt_description_36 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 37 id, txt_description_37 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 38 id, txt_description_38 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 39 id, txt_description_39 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 40 id, txt_description_40 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 41 id, txt_description_41 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 42 id, txt_description_42 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 43 id, txt_description_43 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 44 id, txt_description_44 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 45 id, txt_description_45 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 46 id, txt_description_46 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 47 id, txt_description_47 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 48 id, txt_description_48 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 49 id, txt_description_49 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 50 id, txt_description_50 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 51 id, txt_description_51 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 52 id, txt_description_52 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 53 id, txt_description_53 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 54 id, txt_description_54 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 55 id, txt_description_55 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 56 id, txt_description_56 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 57 id, txt_description_57 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 58 id, txt_description_58 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 59 id, txt_description_59 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 60 id, txt_description_60 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1 UNION
    SELECT 61 id, txt_info2 name FROM ngkbm_template_data_sets_ where practice_id = '0001' and txt_data_set = 'Protocols' and chk_label_values = 1
    ) tmp_table
    ORDER BY id
    

    【讨论】:

    • 1) 我会使用UNION ALL 而不是UNION,因为UNION 强制SQL Server 删除重复的行。这意味着(通常)SORT(不利于大数据集的性能)。在这种情况下,我认为没有必要删除重复的行。 2) 此解决方案将从ngkbm_template_data_sets_ 表中读取行不是一次而是第60 次。我的解决方案强制 SQL Server 从ngkbm_template_data_sets_ 读取数据一次。
    • 不会有重复,所以虽然它不会产生负面影响,但除了一些性能之外,它不会产生太大影响。交叉应用中的所有这些联合选择不会导致查询从表中读取 60 次?可能是我弄错了,但是好像union是否在apply中,还是有60个select。
    • 1) 也许在这种情况下,SELECT 子句中有一个具有 UNIQUE 约束的列(只是一个示例),并且 SQL Server 足够聪明,可以从执行计划中删除不必要的 Sort/@ 987654328@运营商。 2)很好的问题。 SELECT @varsSELECT columns FROM table 之间存在差异。对于第一个SELECT,SQL Server 使用Constant Scan 运算符。第二个SELECT 生成逻辑(也可能是物理)读取。我更改了答案,并包含了一个测试。请参阅[编辑 1] 部分。
    猜你喜欢
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-03
    • 2010-12-17
    • 1970-01-01
    • 2011-03-30
    • 2020-05-20
    相关资源
    最近更新 更多