你好我有下表
ITEM MarkRange
ENG-MA 20-39%
A1-014 40-59%
A2-10 1-9%
15-69 20-39%
但是我想要一个透视查询,使我的结果看起来像这样
20-39% 40-59% 1-9%
ENG-MA A1-014 A2-10
15-69
我已经使用“项目”列上的最大值编写了PIVOT查询,但是它没有工作,因为它只返回了每个标记范围的一个项目。欢迎任何建议。谢谢
编辑:这是我的查询
select *
from
(
select ITEM, MarkRange
from #unw
) src
pivot
(
max(item )
for MarkRange in ([1.9%], [20-39%], [10-19%])
) piv;
但是当标记值包含大量项目
时,每个标记只能获得1行答案 0 :(得分:3)
已知标记范围的简单解决方案可能是使用条件aggeregation。
drop table t;
go
create table t(ITEM varchar(20), MarkRange varchar(20))
insert into t values
('ENG-MA' , '20-39%'),
('A1-014' , '40-59%'),
('A2-10' , '1-9%'),
('15-69' , '20-39%')
select --rn,
max(case when markrange = '1-9%' then item else '' end) as '1-9%',
max(case when markrange = '20-39%' then item else '' end) as '20-39%',
max(case when markrange = '40-59%' then item else '' end) as '40-59%'
from
(
select markrange, item , row_number() over (partition by markrange order by item) rn from t
) s
group by rn
1-9% 20-39% 40-59%
-------------------- -------------------- --------------------
A2-10 15-69 A1-014
ENG-MA
(2 row(s) affected)
如果标记范围未知,则以编程方式创建sql语句并运行动态sql。
答案 1 :(得分:0)
我认为你不能使用没有聚合的数据透视表。 另一种方法是使用row_number和full join。
这样的事情:
;WITH T AS (
SELECT *
FROM (VALUES
('ENG-MA','20-39%')
,('A1-014','40-59%')
,('A2-10','1-9%')
,('15-69','20-39%')
) AS V(ITEM, MarkRange)
)
, R1 AS (
SELECT
ITEM
, ROW_NUMBER() OVER (ORDER BY ITEM) AS ID
FROM T WHERE MarkRange = '20-39%'
)
, R2 AS (
SELECT
ITEM
, ROW_NUMBER() OVER (ORDER BY ITEM) AS ID
FROM T WHERE MarkRange = '40-59%'
)
, R3 AS (
SELECT
ITEM
, ROW_NUMBER() OVER (ORDER BY ITEM) AS ID
FROM T WHERE MarkRange = '1-9%'
)
SELECT R1.ITEM AS [20-39%], R2.ITEM AS [40-59%], R3.ITEM AS [1-9%]
FROM R1
FULL JOIN R2 ON R1.ID = R2.ID
FULL JOIN R3 ON R1.ID = R3.ID OR R2.ID = R3.ID
;
答案 2 :(得分:0)
我使用STUFF和FOR XML PATH('')方法聚合逗号分隔的范围内的项目。
--create table #unw( ITEM varchar(10), MarkRange varchar(10))
/*
insert into #unw values
('ENG-MA','20-39%'),
('A1-014','40-59%'),
('A2-10','1-9%'),
('15-69','20-39%')
*/
;with cte as (
select
case when MarkRange = '1-9%' then item end as [1-9%],
case when MarkRange = '20-39%' then item end as [20-39%],
case when MarkRange = '40-59%' then item end as [40-59%]
from #unw
)
select distinct
stuff(
(
select isnull(',' + [1-9%],'')
from cte
for xml path('')
),1,1,'') as [1-9%],
stuff(
(
select isnull(',' + [20-39%],'')
from cte
for xml path('')
),1,1,'') as [20-39%],
stuff(
(
select isnull(',' + [40-59%],'')
from cte
for xml path('')
),1,1,'') as [40-59%]
from cte
查询的输出如下
我正在替换逗号','使用回车+换行符如下;with cte as (
select
case when MarkRange = '1-9%' then item end as [1-9%],
case when MarkRange = '20-39%' then item end as [20-39%],
case when MarkRange = '40-59%' then item end as [40-59%]
from #unw
)
select
replace(cast([1-9%] as varchar(30)), ',', CHAR(13)+CHAR(10)) [1-9%],
replace(cast([20-39%] as varchar(30)), ',', CHAR(13)+CHAR(10)) [20-39%],
replace(cast([40-59%] as varchar(30)), ',', CHAR(13)+CHAR(10)) [40-59%]
from
(
select distinct
stuff(
(
select isnull(',' + [1-9%],'')
from cte
for xml path('')
),1,1,'') as [1-9%],
stuff(
(
select isnull(',' + [20-39%],'')
from cte
for xml path('')
),1,1,'') as [20-39%],
stuff(
(
select isnull(',' + [40-59%],'')
from cte
for xml path('')
),1,1,'') as [40-59%]
from cte
) t
答案 3 :(得分:0)
该方法的基本难点在于每个列都被视为一个桶,其中的项目应该从顶部列出,并且每行的相邻值之间没有任何关系(除了它们的行号)。
请注意,此代码未经测试 - 我不确定您是否可以在列标题中包含百分号。
另外,你需要引用一个数字表 - 如果你还没有数字表,这很容易实现,我会留给读者作为练习。
编辑:忘记在每次加入时都包含MarkRange条件!
WITH base_data AS
(
SELECT
Item
,MarkRange
,ROW_NUMBER() OVER (PARTITION BY MarkRange ORDER BY Item) AS line_num
FROM
#unw
)
,row_structure AS
(
SELECT
number AS line_num
FROM
numbers_table --you need to either reference a numbers table or a number sequence generator here
WHERE
number BETWEEN 1 AND (SELECT MAX(line_num) FROM base_data)
)
SELECT
twenty_to_thirtynine.Item AS [20-39%]
,forty_to_fiftynine.Item AS [40-59%]
,one_to_nine.Item AS [1-9%]
FROM
row_structure
LEFT JOIN
base_data AS one_to_nine
ON (one_to_nine.line_num = row_structure.line_num)
AND (one_to_nine.MarkRange = '1-9%')
LEFT JOIN
base_data AS twenty_to_thirtynine
ON (twenty_to_thirtynine.line_num = row_structure.line_num)
AND (twenty_to_thirtynine.MarkRange = '20-39%')
LEFT JOIN
base_data AS forty_to_fiftynine
ON (forty_to_fiftynine.line_num = row_structure.line_num)
AND (forty_to_fiftynine.MarkRange = '40-59%')
ORDER BY
row_structure.line_num