【问题标题】:Join with dynamic pivot (version 2)加入动态枢轴(版本 2)
【发布时间】:2010-10-28 14:24:34
【问题描述】:

我有一些数据表:

类别

CategoryID     CategoryName

1              Home
2              Contact
3              About

位置

PositionID     PositionName

1              Main menu
2              Left menu
3              Right menu

...(以后可以添加新行)

类别位置

CPID   CID    PID    COrder

1      1      1      1 
2      1      2      2
3      1      3      3
4      2      1      4
5      2      3      5

如何制作这样的表格:

CID    CName     MainMenu   LeftMenu   RightMenu

1      Home      1          2          3
2      Contact   4          0          5
3      About     0          0          0

如果稍后添加新的类别或位置行,查询应自动反映更改,例如:

CID    CName     MainMenu   LeftMenu   RightMenu   BottomMenu

1      Home      1          2          3           0
2      Contact   4          0          5           0
3      About     0          0          0           0
4      News      0          0          0           0

【问题讨论】:

  • 你能解释你想要完成什么吗?只是列出一堆表真的没有多大帮助......
  • 这很像你之前在stackoverflow.com/questions/904028/…提出的问题
  • 我想列出类别的顺序。一个类别可以以不同的顺序放置在多个位置。并且如果增加了一个新的位置,这个位置的类别的顺序应该是0

标签: sql sql-server sql-server-2008 join


【解决方案1】:

以下动态查询似乎有效:

declare @columnlist nvarchar(4000)
select @columnlist = IsNull(@columnlist + ', ', '') + '[' + PositionName + ']'
from #Position

declare @query nvarchar(4000)
select @query = '
    select *
    from (
        select CategoryId, CategoryName, PositionName, 
                IsNull(COrder,0) as COrder
        from #Position p
        cross join #Category c
        left join #CategoryPosition cp 
                on cp.pid = p.PositionId 
                and cp.cid = c.CategoryId
    ) pv
    PIVOT (max(COrder) FOR PositionName in (' + @columnlist + ')) as Y
    ORDER BY CategoryId, CategoryName
'

exec sp_executesql @query

一些澄清:

  • @columnlist 包含动态字段列表,由 Positions 表构建
  • 交叉连接会创建一个包含所有类别和所有职位的列表
  • 左连接寻找对应的 COrder
  • max() 选择每个类别+位置的最高 COrder(如果有多个)
  • PIVOT() 将各种 PositionNames 转换为单独的列

附:我的表名以 # 开头,因为我将它们创建为临时表。删除 # 以引用永久表。

附注 2。如果有人想尝试一下,这里有一个脚本可以在这个问题中创建表格:

set nocount on 

if object_id('tempdb..#Category') is not null drop table #Category
create table #Category (
    CategoryId int identity,
    CategoryName varchar(50)
)

insert into #Category (CategoryName) values ('Home')
insert into #Category (CategoryName) values ('Contact')
insert into #Category (CategoryName) values ('About')
--insert into #Category (CategoryName) values ('News')

if object_id('tempdb..#Position') is not null drop table #Position
create table #Position (
    PositionID int identity,
    PositionName varchar(50)
)

insert into #Position (PositionName) values ('Main menu')
insert into #Position (PositionName) values ('Left menu')
insert into #Position (PositionName) values ('Right menu')
--insert into #Position (PositionName) values ('Bottom menu')

if object_id('tempdb..#CategoryPosition') is not null 
    drop table #CategoryPosition
create table #CategoryPosition (
    CPID int identity,
    CID int,
    PID int,
    COrder int
)

insert into #CategoryPosition (CID, PID, COrder) values (1,1,1)
insert into #CategoryPosition (CID, PID, COrder) values (1,2,2)
insert into #CategoryPosition (CID, PID, COrder) values (1,3,3)
insert into #CategoryPosition (CID, PID, COrder) values (2,1,4)
insert into #CategoryPosition (CID, PID, COrder) values (2,3,5)

【讨论】:

    【解决方案2】:

    由于 PIVOT 需要静态列列表,我认为基于动态 sql 的方法确实是您可以做的所有事情:http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx

    【讨论】:

      【解决方案3】:

      正如几位发帖人所提到的,使用 PIVOT 命令的动态 SQL 是可行的方法。我不久前写了一个名为pivot_query.sql 的存储过程,这对于这个目的非常方便。它的工作原理是这样的:

      -- Define a query of the raw data and put it in a variable (no pre-grouping required)
      declare @myQuery varchar(MAX);
      
      set @myQuery = '
      select
         cp.cid,
         c.CategoryName,
         p.PositionName,
         cp.COrder
      from
         CategoryPosition cp
      
         JOIN Category c
            on (c.CategoryId = cp.cid)
      
         JOIN Position p
            on (p.PositionId = cp.pid)';
      
      -- Call the proc, passing the query, row fields, pivot column and summary function
      exec dbo.pivot_query @myQuery, 'CategoryName', 'PositionName', 'max(COrder) COrder'
      

      pivot_query 调用的完整语法是:

      pivot_query '<query>', '<field list for each row>', '<pivot column>', '<aggregate expression list>', '[<results table>]', '[<show query>]'
      

      source code 顶部的 cmets 中有更多解释。

      这个 proc 的几个优点是您可以指定多个汇总函数,例如 max(COrder)、min(COrder) 等,并且它可以选择将输出存储在表中以防您想加入汇总数据与其他信息。

      【讨论】:

        【解决方案4】:

        我猜您需要使用 PIVOT 进行选择。默认情况下,数据透视仅选择列的静态列表。网上有一些处理动态列枢轴的解决方案,例如herehere

        【讨论】:

          【解决方案5】:

          我的建议是将您的数据作为简单的连接返回,并让前端对其进行排序。 SQL 在某些方面非常出色,但这个特殊问题似乎是前端应该做的事情。当然,如果不了解您的全部情况,我无法知道这一点,但这是我的预感。

          【讨论】:

            猜你喜欢
            • 2017-09-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-26
            • 1970-01-01
            相关资源
            最近更新 更多