我想要一个没有聚合sql的数据透视查询

时间:2018-01-05 10:21:35

标签: sql sql-server tsql pivot aggregate

你好我有下表

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行

4 个答案:

答案 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)

这是你想要的吗? 标记范围下的Concatenating item values

我使用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

查询的输出如下

enter image description here

我正在替换逗号','使用回车+换行符如下

;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