我有一个奇怪的SQL问题。
我有2个表,比如产品(带有列pid和pname)和规则(带有列rid和rname),这两个表没有任何共同之处。 product表有100行,规则表有16行。
我需要以这样的方式编写查询:我获得的结果将pname作为第一列,其余列是表规则的16行。换句话说,我需要在结果的列中转换表规则的行。因此,在结果中,我应该能够有100行(产品表中的所有pnames)和17列(pname和规则表中的16行)。
你能帮我写一下这样的疑问吗?我尝试使用case语句将行转换为列,但是当与product表的结果结合使用时,我得到的行数是产品和规则表的笛卡尔积,我不想要。我希望行数等于product表中的行,并且列数等于规则表中的行。你能帮忙吗?
答案 0 :(得分:1)
如果您使用的是SQL Server 2005+,则可以使用Pivot和Unpivot命令将行转换为列,将列转换为行。
答案 1 :(得分:1)
这称为Pivot。要拥有动态数量的列,您可能必须使用动态SQL-从另一个查询动态创建查询,并使用任何可用的eval方法。根据您使用的语言,调用代码可以轻松处理。我建议重构以另一种方式进行,或者为几个小时的学习做好准备。如果没有更多信息 - 数据库模式,以及您正在使用的sql db,我无法真正帮助您查询。
这是一个相当复杂的例子,虽然我不确定它会有多大帮助。
ALTER PROCEDURE [dbo].[CMS_GetCollection]
@sectionContentTemplateID int
,@count int = null
AS
BEGIN
SET NOCOUNT ON;
SET NOCOUNT ON;
declare @columns varchar(max)
select
@columns = COALESCE(@columns + ',[' + cte.name + '/' + a.name + ']', '[' + cte.name + '/' + a.name + ']')
from tcmssection_contenttemplate sct
inner join tcmssection s on s.sectionid = sct.sectionid
inner join tcmscontenttemplate ct on ct.contenttemplateid = sct.contenttemplateid
inner join tcmscontenttemplate_element cte on cte.contenttemplateid = ct.contenttemplateid
inner join tcmselement e on cte.elementid = e.elementid
inner join tcmsattribute a on e.elementid = a.elementid
where
a.isadmin = 0
and sct.sectioncontenttemplateid = @sectionContentTemplateID
declare @query varchar(max)
set @query =
'select ' + case when @count is not null then
' top ' + convert(varchar(10),@count) else '' end + '
[url]
,pageId,pageName,sortOrder
,[date]
, ' + @columns + '
from (
select
s.domainpath + p.filename as [url]
,cte.name + ''/'' + a.name as [element.attribute]
,isnull(pva.valuevarchar, isnull(pva.valuetext,'''')) as [value]
,pv.datepublished as [date],isnull(p.sortOrder,0) as sortOrder,p.pageID,p.name as pageName
from tcmssection_contenttemplate sct
inner join tcmssection s on s.sectionid = sct.sectionid
inner join tcmspage p on p.sectioncontenttemplateid = sct.sectioncontenttemplateid
inner join tcmscontenttemplate ct on ct.contenttemplateid = sct.contenttemplateid
inner join tcmscontenttemplate_element cte on cte.contenttemplateid = ct.contenttemplateid
inner join tcmselement e on cte.elementid = e.elementid
inner join tCMSPageVersion pv on p.pageID = pv.pageID
and pv.pageVersionID = (
select top 1 pageVersionID
from tCMSPageVersion
where pageID = p.pageID and datePublished is not null and datecancelled is null
order by datePublished desc
)
inner join tcmsattribute a on e.elementid = a.elementid
left outer join tcmspageversion_element pve on pve.pageversionid = pv.pageversionid
and pve.elementid = e.elementid and pve.name = cte.name
left outer join tcmspageversion_attribute pva on pva.attributeid = a.attributeid
and pve.pageversionelementid = pva.pageversionelementid
where
p.isDeleted = 0
and a.isadmin = 0
and sct.sectioncontenttemplateid = ' + convert(varchar(10), @sectionContentTemplateID) + '
) [data]
pivot (
max([value])
for [element.attribute]
in ( ' + @columns + ' )
) as [pivot]
order by [date] desc'
execute(@query)
END
答案 2 :(得分:1)
这适用于一定数量的列。如果您需要的列数将发生变化,您还可以使用动态SQL来提供类似的内容。
SELECT
products.pname,
MAX(CASE WHEN rules.rname = 'Rule 0' THEN products.pid * rules.rid) AS pid_r0,
MAX(CASE WHEN rules.rname = 'Rule 1' THEN products.pid * rules.rid) AS pid_r1,
MAX(CASE WHEN rules.rname = 'Rule 2 'THEN products.pid * rules.rid) AS pid_r2,
...
FROM products
CROSS JOIN rules
GROUP BY products.pname;
答案 3 :(得分:0)
老实说,我不得不暂时处理内部数据处理问题(与SQL行的最大长度为24000字节左右)。我的解决方案是使用XML数据类型,因为它使您能够尽可能轻松地完成大多数这些随机类型的数据转换。其他作者提出的Pivot问题是Pivots依赖聚合函数来成功 - 这是我从未想过的事情。