从数据库获取特定数据而不循环

时间:2015-04-08 09:45:23

标签: sql sql-server select

我有一张表格,其中单个用户的数据是这样的

ID - 数字 - 子编号 - 名称

1 101 201101 Jack
2 101 201102 Jack
3 101 201103 Jack
4 101 201107 Jack
5 101 201111 Jack
6 101 201112 Jack
7 101 201113 Jack
8 101 201161 Jack
9 101 201162 Jack
10 101 201163 Jack
11 101 201164 Jack
12 101 201165 Jack

我想获得这样的记录without using any kind of loop.

数字 - 名称 - 子编号

101 Jack (201101-201103, 201107, 201111-201113, 201161-201165)

目前我能够以此

的形式获取记录

数字 - 名称 - 子编号

101 Jack (201101,201102,201103, 201107, 201111,201112,201113, 201161,201162,201163,201164,201165)

查询以获得更高的结果是

SELECT  Number, Name
,STUFF((SELECT ', ' + CAST(SubNumber AS VARCHAR(50)) [text()]
     FROM [Table] 
     WHERE Number= t.Number
     FOR XML PATH(''), TYPE)
    .value('.','NVARCHAR(MAX)'),1,2,' ') SubNumber
FROM [Table] t
GROUP BY Number,Name
having Number= '101'

我完全被困在这里。任何形式的帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

试试这个。对于MS SQL Server 2012 +:

DECLARE @t TABLE
    (
      ID INT ,
      Number INT ,
      Code INT
    )

INSERT  INTO @t
VALUES  ( 1, 201101, 101 ),
        ( 2, 201102, 101 ),
        ( 3, 201103, 101 ),
        ( 4, 201107, 101 ),
        ( 5, 201111, 101 ),
        ( 6, 201112, 101 ),
        ( 7, 201113, 101 ),
        ( 8, 201161, 101 ),
        ( 9, 201162, 101 ),
        ( 10, 201163, 101 ),
        ( 11, 201164, 101 ),
        ( 12, 201165, 101 ),
        ( 13, 201166, 102 ),
        ( 14, 201169, 102 ),
        ( 15, 201175, 102 ),
        ( 16, 201176, 102 ),
        ( 17, 201177, 102 );

WITH    cte1
          AS ( SELECT   * ,
                        CASE WHEN number
                                  - LAG(Number) OVER ( PARTITION BY Code ORDER BY ID ) = 1
                             THEN 0
                             ELSE 1
                        END AS lg
               FROM     @t
             ),
        cte2
          AS ( SELECT   * ,
                        SUM(lg) OVER ( PARTITION BY Code ORDER BY ID ) AS s
               FROM     cte1
             ),
        cte3
          AS ( SELECT   * ,
                        MIN(Number) OVER ( PARTITION BY Code, s ) AS mi ,
                        MAX(Number) OVER ( PARTITION BY Code, s ) AS ma
               FROM     cte2
             ),
        cte4
          AS ( SELECT   Code ,
                        mi ,
                        ma
               FROM     cte3
               GROUP BY Code ,
                        mi ,
                        ma
             )
    SELECT  code ,
            STUFF((SELECT   ', '
                            + CASE WHEN mi <> ma
                                   THEN CAST(mi AS NVARCHAR(MAX)) + '-'
                                        + CAST(ma AS NVARCHAR(MAX))
                                   ELSE CAST(mi AS NVARCHAR(MAX))
                              END
                   FROM     cte4
                   WHERE    Code = t.Code
            FOR   XML PATH('') ,
                      TYPE)
    .value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS Number
    FROM    cte4 t
    GROUP BY Code    

输出:

code    Number
101     201101-201103, 201107, 201111-201113, 201161-201165
102     201166, 201169, 201175-201177

答案 1 :(得分:0)

首先,您应该为每个时间间隔选择开始和结束(请参阅CT - 视图),然后为每个时间间隔使用格式START-FINISH形成字符串(请参阅CT2视图)。在这里你还应该处理start = finish的情况(参见CASE语句)。然后使用您的查询为每个Name分组和连接字符串。

WITH CT AS
(
 SELECT Id,Number, SubNumber as StartNum, Null As EndNumber, Name 
  FROM T
  WHERE NOT EXISTS (SELECT SubNumber FROM T as T1 
                    WHERE T1.Number=T.Number AND T1.SubNumber+1=T.Subnumber)
 UNION 
 SELECT Id,Number,Null as StartNum, SubNumber As EndNumber, Name 
  FROM T
  WHERE NOT EXISTS (SELECT SubNumber FROM T as T1 
                    WHERE T1.Number=T.Number AND T1.SubNumber-1=T.Subnumber)
),
 CT2 AS
 (
   SELECT ID,Number,
          CAST(StartNum AS VARCHAR(50)) 
          + (SELECT TOP 1 
                CASE WHEN T3.EndNumber = CT.StartNum 
                     THEN '' 
                     ELSE '-' +CAST(T3.EndNumber AS VARCHAR(50)) 
                END 
              FROM CT as T3 
                WHERE T3.Number=CT.Number 
                      AND T3.EndNumber>=CT.StartNum
             ORDER BY EndNumber) as SubNumber  
           ,Name
   FROM CT 
    WHERE EndNumber IS NULL
  )

SELECT  Number, Name
,STUFF((SELECT ', ' + SubNumber [text()]
     FROM CT2 
     WHERE Number= t.Number
     FOR XML PATH(''), TYPE)
    .value('.','NVARCHAR(MAX)'),1,2,' ') SubNumber
FROM CT2 t
GROUP BY Number,Name
HAVING Number= '101'  

SQLFiddle demo