我有一些数据表:
类别
CategoryID CategoryName
1 Home
2 Contact
3 About
位置
PositionID PositionName
1 Main menu
2 Left menu
3 Right menu
...(稍后可以添加新行)
CategoryPosition
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
答案 0 :(得分:2)
以下动态查询似乎有效:
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
一些澄清:
P.S。我的表名以#开头,因为我将它们创建为临时表。删除#以引用永久表。
P.S.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)
答案 1 :(得分:1)
由于PIVOT需要一个静态列列表,我认为基于动态sql的方法实际上就是你可以做的所有事情:http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
答案 2 :(得分:1)
正如几张海报所提到的,使用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顶部的评论中对此进行了解释。
此过程的一些优点是您可以指定多个汇总函数,如max(COrder),min(COrder)等。它可以选择将输出存储在表中,以防您想要加入汇总数据与其他信息。
答案 3 :(得分:0)
答案 4 :(得分:0)
我的建议是将您的数据作为简单连接返回,并让前端对其进行排序。 SQL有一些优秀的东西,但这个特殊问题似乎是前端应该做的事情。当然,我不知道如果不知道你的情况,那就是我的预感。