代码之家  ›  专栏  ›  技术社区  ›  Ascalonian

选择“返回动态列”

  •  5
  • Ascalonian  · 技术社区  · 16 年前

    我需要做的是编写一个视图,它将返回一些公共数据,然后在一行中列出服务选项。例如:

    Standard Id | Description | SO #1 | SO #2 | SO #3 | ... | SO #21 | SO Count
    1           | One         | A     | B     | C     | ... | G      |  21
    2           | Two         | A     |       |       | ... |        |  1
    3           | Three       | B     | D     | E     | ... |        |  3
    

    有什么办法吗?

    我开始的地方就在下面。它只为每个服务提供返回多行,而它们需要在一行上。

    SELECT *
      FROM SERVICE_OFFERINGS
     WHERE STANDARD_KEY IN (SELECT STANDARD_KEY
                              FROM STANDARDS)
    

    所以这里有一个SQL,它返回我想要的所有内容,但是由于有11个服务选项,它将返回11行。我一直在尝试透视表,但似乎无法用它来解决问题。有人能帮忙做一个代码示例吗?

    SELECT DISTINCT stpc.standard_key,
                    stpc.test_id,
                    NULL AS pricebook_id,
                    stpc.stabdard_name AS description,
                    stpc.date_start AS begin_date,
                    stpc.date_end AS end_date,
                    sopd.service_offering_id
      FROM STANDARDS stpc,
           SERVICE_OFFERINGS sopd
     WHERE 1=1
       AND sopd.standard_key = stpc.standard_key
     ORDER BY stpc.standard_key, sopd.service_offering_id
    

    更新

    因为数据库不假设透视表(并且无法理解XML建议),所以我不得不使用一些复杂的SQL来让它工作。我用的是:

    select stpc.oracle_product_code AS test_id,
           CASE WHEN stpc.store_key = 200 THEN 'CE_USAUSD09'
                WHEN stpc.store_key = 210 THEN 'CE_CANCAD09' END AS pricebook_id,
           stpc.standard_name AS its_test_desc,
           CONVERT(VARCHAR(10), stpc.date_start, 101) AS begin_date,
           CONVERT(VARCHAR(10), stpc.date_end, 101) AS end_date,
           MAX(CASE WHEN rn = 1 THEN b.service_offering_id END) AS SERVICE_OFFERING_1,
           MAX(CASE WHEN rn = 2 THEN b.service_offering_id END) AS SERVICE_OFFERING_2,
           MAX(CASE WHEN rn = 3 THEN b.service_offering_id END) AS SERVICE_OFFERING_3,
           MAX(CASE WHEN rn = 4 THEN b.service_offering_id END) AS SERVICE_OFFERING_4,
           MAX(CASE WHEN rn = 5 THEN b.service_offering_id END) AS SERVICE_OFFERING_5,
           MAX(CASE WHEN rn = 6 THEN b.service_offering_id END) AS SERVICE_OFFERING_6,
           MAX(CASE WHEN rn = 7 THEN b.service_offering_id END) AS SERVICE_OFFERING_7,
           MAX(CASE WHEN rn = 8 THEN b.service_offering_id END) AS SERVICE_OFFERING_8,
           MAX(CASE WHEN rn = 9 THEN b.service_offering_id END) AS SERVICE_OFFERING_9,
           MAX(CASE WHEN rn = 10 THEN b.service_offering_id END) AS SERVICE_OFFERING_10,
           MAX(CASE WHEN rn = 11 THEN b.service_offering_id END) AS SERVICE_OFFERING_11,
           MAX(CASE WHEN rn = 12 THEN b.service_offering_id END) AS SERVICE_OFFERING_12,
           MAX(CASE WHEN rn = 13 THEN b.service_offering_id END) AS SERVICE_OFFERING_13,
           MAX(CASE WHEN rn = 14 THEN b.service_offering_id END) AS SERVICE_OFFERING_14,
           MAX(CASE WHEN rn = 15 THEN b.service_offering_id END) AS SERVICE_OFFERING_15,
           MAX(CASE WHEN rn = 16 THEN b.service_offering_id END) AS SERVICE_OFFERING_16,
           MAX(CASE WHEN rn = 17 THEN b.service_offering_id END) AS SERVICE_OFFERING_17,
           MAX(CASE WHEN rn = 18 THEN b.service_offering_id END) AS SERVICE_OFFERING_18,
           MAX(CASE WHEN rn = 19 THEN b.service_offering_id END) AS SERVICE_OFFERING_19,
           MAX(CASE WHEN rn = 20 THEN b.service_offering_id END) AS SERVICE_OFFERING_20,
           MAX(CASE WHEN rn = 21 THEN b.service_offering_id END) AS SERVICE_OFFERING_21,
           MAX(rn) AS service_offering_count
    FROM (
    select standard_key,
           service_offering_id, 
           row_number() over (partition by standard_key order by standard_key) rn
    from SERVICE_OFFERINGS
    ) B,
    SERVICE_OFFERINGS sopd,
    STANDARDS stpc
    where b.service_offering_id = sopd.service_offering_id
    AND b.standard_key = stpc.standard_key
    AND sopd.standard_key = stpc.standard_key
    AND stpc.store_key IN (200,210)
    AND stpc.create_date > '03/29/2010'
    group by stpc.oracle_product_code,stpc.store_key,stpc.standard_name,stpc.date_start,stpc.date_end
    
    3 回复  |  直到 16 年前
        1
  •  3
  •   Martin Smith    12 年前

    您可以为此使用透视功能。

    http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=PIVOTData

    您应该结合使用FOR XML和SplitToColumns,而不是PIVOT。

    FOR XML 把你的产品集中到一个专栏 Concatenating Row Values in Transact-SQL

    然后使用CTE样式的函数将单个单元格分解为列,如下所示 http://www.sqlservercentral.com/articles/CTE/67974/

    这将为您提供一个以您需要的方式旋转出来的表格。

    然后进行算术运算,得到非空列的计数,最后得到所需的计数。

        2
  •  1
  •   Philip Kelley    16 年前

    21列是否总是相同的,或者您最多只能显示21列(例如,数百列)?如果实际列可能因查询而异,则必须研究如何编写动态查询(将查询构建为字符串—合并要透视的列—然后执行字符串)。

        3
  •  1
  •   Claudia    16 年前

    但是如果列数在1到21之间变化,则必须编写一个动态查询。

    SELECT standard_key, stabdard_name, [A] as SO1, [B] as SO2, [C] as SO3, [D] as SO4, [E] as SO5....-- and so on with the other columns
    FROM 
    (SELECT ST.standard_key, ST.stabdard_name, SO.service_offering_id
    FROM SERVICE_OFFERINGS SO
        INNER JOIN STANDARDS ST
            ON SO.standard_key= ST.standard_key)p
    PIVOT
    (
    MAX (service_offering_id)
    FOR service_offering_id IN
    ( [A], [B], [C], [D], [E]....-- and so on with the other values)
    ) AS pvt
    ORDER BY standard_key
    

    如果列可能不同,您可以尝试以下方法:

    declare @sql nvarchar(max)
    declare @sql2 nvarchar(max)
    
    SET @sql2=''
    set @sql = '
    select
        standard_key, stabdard_name,'
    
    select @sql = @sql + '['+ service_offering_id + '] AS [SO' +  convert(varchar, Row_number() OVER (ORDER BY  service_offering_id))+ '],'
    from (select distinct [service_offering_id] from [SERVICE_OFFERINGS]) as moduleids
    
    select @sql2 = @sql2 + '['+ service_offering_id + '],'
    from (select distinct [service_offering_id] from [SERVICE_OFFERINGS]) as moduleids
    
    set @sql2 = substring(@sql2,1,len(@sql2)-1)
    
    set @sql = substring(@sql,1,len(@sql)-1) + '
    FROM 
    (SELECT ST.standard_key, ST.stabdard_name, SO.service_offering_id
    FROM SERVICE_OFFERINGS SO
        INNER JOIN STANDARDS ST
            ON SO.standard_key= ST.standard_key)p
    PIVOT
    (
    MAX (service_offering_id)
    FOR service_offering_id IN
    (' + @sql2 + 
    ')) AS pvt
    ORDER BY standard_key'
    
    print @sql
    
    exec sp_executesql @sql