在 ms sql 中旋转 2 列并依次显示数据

Posted

技术标签:

【中文标题】在 ms sql 中旋转 2 列并依次显示数据【英文标题】:pivot 2 columns and show data one after another in ms sql 【发布时间】:2018-02-14 23:06:20 【问题描述】:

下面是我的桌子

我想要的结果如下

通过枢轴我实现了如下

这个但仍然需要一个接一个的列。

下面是我写的查询

DECLARE @pivot1 varchar(8000), DECLARE @pivot2 varchar(8000)

SELECT  @pivot1=coalesce(@pivot1+',','')+'[cust'+cast(number+1 as varchar(10))+']' FROM  master..spt_values where type='p' and  number<=(SELECT max(len(cust1)-len(replace(cust1,',',''))) FROM xyz1)

SELECT  @pivot2=coalesce(@pivot2+',','')+'[city'+cast(number+1 as varchar(10))+']' FROM  master..spt_values where type='p' and  number<=(SELECT max(len(city1)-len(replace(city1,',',''))) FROM xyz1)

SELECT A.*, B.* FROM  (
        select p.*
        from (
        select 
            product,substring(cust, start+2, endPos-Start-2) as token,
            'cust'+cast(row_number() over(partition by product order by start) as varchar(10)) as n
        from (
            select 
                product, Customer, n as start, charindex(',',Customer,n+2) endPos
                from (select number as n from master..spt_values where type='p') num
                cross join 
                (
                    select product, ',' + Customer +',' as cust 
                    from 
                        xyz1
                ) m
            where n < len(cust)-1
            and substring(cust,n+1,1) = ',') as cust
        ) pvt
        Pivot ( max(token)for n in ([cust1],[cust2],[cust3]))p ) A JOIN (
        select 
            product,substring(city, start+2, endPos-Start-2) as token,
            'city'+cast(row_number() over(partition by product order by start) as varchar(10)) as n
        from (
            select 
                product, Customer, n as start, charindex(',',Customer,n+2) endPos
                from (select number as n from master..spt_values where type='p') num
                cross join 
                (
                    select product, ',' + City +',' as city 
                    from 
                        xyz1
                ) m
            where n < len(city)-1
            and substring(city,n+1,1) = ',') as city
        ) pvt
        Pivot ( max(token)for n in ([city1],[city2],[city3]))p ) B

ON A.product = B.product

xyz & xyz1 如下图:

xyz 视图:-

SET ANSI_NULLS ON GO

SET QUOTED_IDENTIFIER ON GO

ALTER view [dbo].[xyz] as  select product, Customer, City from Customer with (nolock) where product IN (1,2)

GO

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO

和 xyz1 视图为:

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO

ALTER view [dbo].[xyz1] as

    SELECT product, Customer, City  ,Customer1=STUFF    (  
        (  
          SELECT  ', '+ CAST(sh.Customer AS VARCHAR(MAX))
          FROM xyz sh
          where sh.product IN (1,2)
          FOR XMl PATH('')  
          
        ),1,1,''  
            )   ,City=STUFF     (  
        (  
          SELECT  ', '+ CAST(sh.City AS VARCHAR(MAX))
          FROM xyz sh
           where sh.product IN (1,2)
          FOR XMl PATH('')
          
        ),1,1,''  
            )       FROM xyz t1         where t1.product IN (1,2)

GO

【问题讨论】:

随心所欲选择列..顺序无关紧要 我无法在 SELECT 子句中指定列名,因为列名是在我 PIVOT 时动态生成的。 你能显示你的代码吗? 我已经更新了@Nithin 的问题 视图在哪里? xyz 和 xyz1 【参考方案1】:

这些列按照您在 SELECT 列表中指定的顺序出现。

如有必要,将您当前的查询转换为 CTE 或派生表,并从中按您想要的顺序使用列执行外部 SELECT。

【讨论】:

我无法在 SELECT 子句中指定列名,因为列名是在我 PIVOT 时动态生成的。 是的,你可以,你只需要动态生成 SELECT 子句,就像动态生成 PIVOT 一样。【参考方案2】:

尝试使用 cte(common table expression) 选择表

;with cte as (SELECT A.*, B.* FROM  (
        select p.*
        from (
        select 
            product,substring(cust, start+2, endPos-Start-2) as token,
            'cust'+cast(row_number() over(partition by product order by start) as varchar(10)) as n
        from (
            select 
                product, Customer, n as start, charindex(',',Customer,n+2) endPos
                from (select number as n from master..spt_values where type='p') num
                cross join 
                (
                    select product, ',' + Customer +',' as cust 
                    from 
                        xyz1
                ) m
            where n < len(cust)-1
            and substring(cust,n+1,1) = ',') as cust
        ) pvt
        Pivot ( max(token)for n in ([cust1],[cust2],[cust3]))p ) A JOIN (
        select 
            product,substring(city, start+2, endPos-Start-2) as token,
            'city'+cast(row_number() over(partition by product order by start) as varchar(10)) as n
        from (
            select 
                product, Customer, n as start, charindex(',',Customer,n+2) endPos
                from (select number as n from master..spt_values where type='p') num
                cross join 
                (
                    select product, ',' + City +',' as city 
                    from 
                        xyz1
                ) m
            where n < len(city)-1
            and substring(city,n+1,1) = ',') as city
        ) pvt
        Pivot ( max(token)for n in ([city1],[city2],[city3]))p ) B

ON A.product = B.product)

select product,cust1,city1,cust2,city2,cust3,city3 from cte;

【讨论】:

如果我的数据不同,它会起作用吗,比如 cust 和 city 可能会有所不同,max 可以是 10,min 可以是 1。

以上是关于在 ms sql 中旋转 2 列并依次显示数据的主要内容,如果未能解决你的问题,请参考以下文章

SQL - 将行旋转到列并采用笛卡尔积

如何使 Excel 在 MS SQL 2017 中任意旋转(交叉连接 + 循环)

如何在 T-SQL 中将列与旋转其他列相加

如何保持某些列原样并动态旋转 SQL Server 2012 中的最后一列 [重复]

MS Access 2007 在查询中旋转数据并从 Excel 调用

如何在 bigquery 中旋转我的 sql 表?