【问题标题】:How to get below query如何获得以下查询
【发布时间】:2019-10-10 09:51:29
【问题描述】:

我有一个表,其中一个字段名为City

以下是数据。

城市

--------
A
B
C
D
E
F
G
H

输出也将作为列

编写查询或存储过程或函数?

如果通过2,查询结果会在下面

Col1  Col2
A      B
C      D
E      F
G      H

如果通过3,查询结果会在下面

Col1 Col2 Col3
A     B     C
D     E     F
G     H

如果通过4,查询结果会在下面

Col1 Col2 Col3 Clo4
A     B     C    D
E     F     G    H 

--Here script for creating and adding data into temp table
create table #Cities( City varchar(max) )

insert into #Cities values
( 'A' ),
( 'B' ),
( 'C' ),
( 'D' ),
( 'E' ),
( 'F' ),
( 'G' ),
( 'H' )


declare @what_I_pass as int = 2; -- Here pass the number you want.
 with Q1 as
(
    select *, ROW_NUMBER() over (order by City) - 1 as n
    from #Cities
),
Q2 as
(
    select City, n / @what_I_pass as rn, n % @what_I_pass as cn
    from Q1
)

select (stuff((select ' ' + City from Q2 as q where q.rn = Q2.rn order by cn for xml path('')), 1, 1, '')) as Result
from Q2
group by rn
order by rn

【问题讨论】:

  • 要获取动态列数,需要使用动态SQL。就个人而言,这似乎是您应该在表示层中做的事情。
  • 检查我编辑的答案

标签: sql sql-server tsql sql-server-2008


【解决方案1】:

这样可以:

declare @Cols int = 3  -- We define here how many output columns we want: 1, 2, 3, ... up to 10

create table #Cities( City varchar(max) )
insert into #Cities values
( 'A' ),
( 'B' ),
( 'C' ),
( 'D' ),
( 'E' ),
( 'F' ),
( 'G' ),
( 'H' )
;

with Cities as (
  select City,
         row_number() over (order by City) - 1 as Num
  from #Cities
)
select Col1.City as Col1, Col2.City as Col2, Col3.City as Col3, Col4.City as Col4, Col5.City as Col5, Col6.City as Col6, Col7.City as Col7, Col8.City as Col8, Col9.City as Col9, Col10.City as Col10
from Cities as Rows
     left join Cities as Col1  on 0 < @Cols and Col1.Num =  Rows.Num * @Cols + 0
     left join Cities as Col2  on 1 < @Cols and Col2.Num =  Rows.Num * @Cols + 1
     left join Cities as Col3  on 2 < @Cols and Col3.Num =  Rows.Num * @Cols + 2
     left join Cities as Col4  on 3 < @Cols and Col4.Num =  Rows.Num * @Cols + 3
     left join Cities as Col5  on 4 < @Cols and Col5.Num =  Rows.Num * @Cols + 4
     left join Cities as Col6  on 5 < @Cols and Col6.Num =  Rows.Num * @Cols + 5
     left join Cities as Col7  on 6 < @Cols and Col7.Num =  Rows.Num * @Cols + 6
     left join Cities as Col8  on 7 < @Cols and Col8.Num =  Rows.Num * @Cols + 7
     left join Cities as Col9  on 8 < @Cols and Col9.Num =  Rows.Num * @Cols + 8
     left join Cities as Col10 on 9 < @Cols and Col10.Num = Rows.Num * @Cols + 9
where Rows.Num <= (select max(Num) from Cities) / @Cols

drop table #Cities

输入 3 的结果:

Col1    Col2    Col3    Col4    Col5    Col6    Col7    Col8    Col9    Col10
A       B       C       NULL    NULL    NULL    NULL    NULL    NULL    NULL
D       E       F       NULL    NULL    NULL    NULL    NULL    NULL    NULL
G       H       NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

PS:为避免使用动态 SQL,此查询始终返回固定数量的 10 列,但只填充所需的列。现在您的表示层只需要隐藏不需要的空列。

【讨论】:

    【解决方案2】:

    试试下面的查询:

    --Here script for creating and adding data into temp table
    declare @tbl table ( City varchar(max) )
    
    insert into @tbl values
    ( 'A' ),
    ( 'B' ),
    ( 'C' ),
    ( 'D' ),
    ( 'E' ),
    ( 'F' ),
    ( 'G' ),
    ( 'H' )
    
    declare @howManyCols int = 3;
    
    ;with cte as (
        select City, grp,
               row_number() over (partition by grp order by City) rn
        from (
            select *,
                   (row_number() over (order by City) - 1) % @howManyCols + 1 grp
            from @tbl
        ) a
    )
    -- this query can be generated by dynamic SQL, because you can see pattern in following lft join's
    select c1.City, c2.City, c3.City
    from cte c1
    left join cte c2 on c1.grp = c2.grp - 1 and c1.rn = c2.rn
    left join cte c3 on c2.grp = c3.grp - 1 and c2.rn = c3.rn
    where c1.grp = 1
    

    对于等于三的列数,您会得到:

    【讨论】:

    • 谢谢 Michał Turczyn,您能否为上述结果编写动态查询。
    • @SunilKumar 我会把它留给你 :) 大部分工作都在我的回答中完成 :)
    【解决方案3】:

    试试这个脚本,

    declare @flg int=3--test with 1,2,3,4 ...
    create table #temp(id int identity(1,1),col varchar(10))
    insert into #temp values ('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H')
    
    create table #temp1(id int ,col varchar(10),flag int,rownum int)
    declare @PvtCol varchar(500)=''
    declare @Headcol varchar(500)
    declare @Sql nvarchar(500)
    
    
    WITH CTE
         AS (SELECT id,
                    col,
                    CASE
                        WHEN(id % @flg) = 0
                        THEN @flg
                        ELSE(id % @flg)
                    END flag
             FROM #temp),
         CTE1
         AS (SELECT *,
                    ROW_NUMBER() OVER(PARTITION BY flag
                    ORDER BY id) rownum
             FROM cte)
    
         INSERT INTO #temp1
         (id,
          col,
          flag,
          rownum
         )
                SELECT id,
                       col,
                       flag,
                       rownum
                FROM cte1;
    
    SELECT @PvtCol = COALESCE(@PvtCol + ', ' + QUOTENAME(rownum), QUOTENAME(rownum)),
           @Headcol = COALESCE(@Headcol + ', ' + QUOTENAME(rownum) + ' as ' + 'col', QUOTENAME(rownum) + ' as ' + 'col') + CAST(rownum AS VARCHAR)
    FROM #temp1
    WHERE flag = 1;
    
    SET @PvtCol = STUFF(@PvtCol, 1, 1, '');
    
    SELECT @PvtCol,
           @Headcol;
    
    SET @Sql = 'select flag,' + @Headcol + ' from 
    (
    select flag, col,rownum from #temp1
    )src
    pivot(max(col) for rownum in(' + @PvtCol + ')) as pvt';
    
    PRINT @Sql;
    
    EXECUTE sp_executesql
            @Sql;
    
    DROP TABLE #temp, #temp1;
    

    【讨论】:

      猜你喜欢
      • 2016-11-26
      • 2012-01-11
      • 2021-09-06
      • 2013-08-14
      • 2021-11-17
      • 2013-07-26
      • 1970-01-01
      • 2021-08-28
      • 2019-05-09
      相关资源
      最近更新 更多