2010-04-28 73 views
4

我有两个表格:标准和服务产品。一个标准可以有多个服务产品。每个标准可以有不同数量的与其相关的服务产品。选择返回动态列

我需要做的是编写一个视图,该视图将返回一些常见数据,然后在一行中列出服务产品。例如:

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 

我不知道该怎么写。 SO列的数量设置为特定的数字(在这种情况下为21),所以我们不能超过过去的数字。

关于如何解决这个问题的任何想法?

我开始的地方在下面。当它们需要在一行上时,它仅为每个服务产品返回多行。

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

附加SQL

因此,这里的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 

UPDATE

由于数据库不设透视表(和无法弄清楚的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 

回答

2

您可以使用PIVOT功能。

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

PIVOT相反的,你应该使用FOR XML和SplitToColumns的组合。

使用FOR XML并转动你的产品,以一列Concatenating Row Values in Transact-SQL

然后用CTE风格功能,打破单个细胞成列,在这里http://www.sqlservercentral.com/articles/CTE/67974/

所示。这会给你一个表pivotted出以你需要的方式。

然后做数学运算得到非空列的数量,并在最后得到你需要的计数。

1

是的,数据透视查询是你需要使用的。

21列是否总是相同,或者它可以显示不超过21列(出数百个)?如果实际的colmns可能因查询而异,那么您必须考虑编写动态查询(将查询构建为字符串 - 合并要旋转的列 - 然后执行字符串)。

1

菲利普是对的。如果你总是有21列,那么它是一个简单的Pivot查询。我在这里粘贴一个你可以使用的示例代码。 但是,如果列数在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 

如果colums可能会有所不同哟可以用这样的尝试:

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

谢谢你这么多的例子。我试过运行,显然我需要更新数据库的兼容级别。一旦完成,我一定会检查一下。谢谢! – Ascalonian 2010-04-28 17:50:07