SQL Server 2008中的交叉表2条件

时间:2017-11-08 19:18:53

标签: sql-server crosstab

我需要帮助。

我需要使视图大小与颜色交叉以获得项目平衡

我尝试过常规交叉表,但我不能这样做。

我有这张桌子:

ItemCode    ItemName     Size    Color   Balance
--------------------------------------------------
1           Shirt         S      White      10
1           Shirt         M      White      10
1           Shirt         L      White      10
1           Shirt         S      Black      10
1           Shirt         M      Black      10
1           Shirt         L      Black      10

我需要知道如何使用交叉表查询将此表转换为此结果:

ItemCode    Item Name   Colors     S     M     L
--------------------------------------------------
1           Shirt        White     10    10    10
1           Shirt        Black     10    10    10

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

不确定您尝试了什么,但假设您不需要动态列,基本交叉表(也称为条件聚合)将产生这些结果。

select ItemCode
    , ItemName
    , Color
    , S = MAX(CASE when Size = 'S' then Balance end)
    , M = MAX(CASE when Size = 'M' then Balance end)
    , L = MAX(CASE when Size = 'L' then Balance end)
from SomeTable
group by ItemCode
    , ItemName
    , Color

- 编辑 -

您可以使用动态交叉表来解决此问题。我从Jeff Moden和他的文章中学到了这种技巧。 http://www.sqlservercentral.com/articles/Crosstab/65048/

这是一个完整的工作示例,因此这里也有很多设置。

if OBJECT_ID('tempdb..#Something') is not null
    drop table #Something

create table #Something
(
    ItemCode int
    , ItemName varchar(10)
    , Size char(1)
    , Color varchar(10)
    , Balance int
)

insert #Something values
(1, 'Shirt', 'S', 'White', 10)
, (1, 'Shirt', 'M', 'White', 10)
, (1, 'Shirt', 'L', 'White', 10)
, (1, 'Shirt', 'S', 'Black', 10)
, (1, 'Shirt', 'M', 'Black', 10)
, (1, 'Shirt', 'L', 'Black', 10)

declare @StaticPortion nvarchar(2000) = 
    'with OrderedResults as
    (
        SELECT s.ItemCode
            , s.ItemName
            , s.Color
            , s.Size
            , s.Balance
            , ROW_NUMBER() over(partition by s.ItemCode, s.ItemName, s.Color order by s.Size desc) as RowNum
        FROM #Something s
    )
    select ItemCode
        , ItemName
        , Color';

declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ItemCode
        , ItemName
        , Color 
        order by ItemCode
        , ItemName
        , Color';

--the following cte is a tally table (another trick I learned from Jeff Moden)
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
cteTally(N) AS 
(
    SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E2
)

select @DynamicPortion = @DynamicPortion + 
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Balance end) as ' + sizes.SizeName + CHAR(10)
from cteTally t
join 
(
    values
    ('S', 1)
    ,('M', 2)
    ,('L', 3)
) sizes(SizeName, SizeNum) on sizes.SizeNum = t.N --This would be better if you have a table of sizes you can join to
where t.N <= 
(
    select top 1 Count(s.Size)
    FROM #Something s 
    group by s.ItemCode
        , s.ItemName
        , s.Color
    order by COUNT(*) desc
)


declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;

--you can comment the following. it is here for now so you can view the dynamic sql before it executes
select @SqlToExecute

--Once you are satisfied that the dynamic sql generated is correct simply uncomment the below line
--exec sp_executesql @SqlToExecute