SQL concat整数并将它们与from组合在一起

时间:2018-10-31 09:39:30

标签: sql-server tsql

我是stackoverflow的新手,但我对查询感到困惑。

我有一个SQL表,看起来像这样:

+-------+------------+
| col1  |   col2     |
+-------+------------+
|   1   |     1      |
|   1   |     2      |
|   1   |     3      |
|   1   |     4      |
|   1   |     6      |
+-------+------------+

我不知道如何获得以下结果集:

+-------+------------+
| col1  |SerialNumber|
+-------|------------+
|   1   | 1 to 4, 6  |
+--------------------+

使用XML路径,我可以获得此信息:

+-------+------------+
| col1  |SerialNumber|
+-------|------------+
|   1   | 1,2,3,4,6, |
+--------------------+

这是我对此的查询:

SELECT DISTINCT O.Col1, 
 (SELECT CAST(P.Col2 As varchar(5)) + ',' AS [text()] 
 FROM #Test P 
 WHERE P.Col1 = O.Col1 
 ORDER BY P.Col1 
 FOR XML PATH('')) AS 'SerialNumber'
 FROM #Test O

很抱歉,如果我的问题已经被提出。我也缺少该主题的关键字。

2 个答案:

答案 0 :(得分:5)

测试数据:

CREATE TABLE t(col1 int,col2 int)

INSERT t(col1,col2)VALUES
(1,1),(1,2),(1,3),(1,4),
(1,6),(1,7),(1,8),(1,9),
(1,11),
(1,13),

(2,3),(2,4),(2,5),
(2,7)

带有FOR XML PATH的变体:

SELECT col1,col2,outVal
INTO #temp
FROM
  (
    SELECT
      col1,
      col2,
      outVal,
      ISNULL(LEAD(outVal)OVER(PARTITION BY col1 ORDER BY col2),'') nextOutVal
    FROM
      (
        SELECT
          col1,
          col2,
          CASE
            WHEN col2-1=LAG(col2)OVER(PARTITION BY col1 ORDER BY col2) AND col2+1=LEAD(col2)OVER(PARTITION BY col1 ORDER BY col2)
            THEN 'to'
            ELSE CAST(col2 AS varchar(10))
          END outVal
        FROM t
      ) q
  ) q
WHERE outVal<>nextOutVal
ORDER BY col1,col2

SELECT
  t1.col1,
  REPLACE(STUFF(
    (
      SELECT ','+t2.outVal
      FROM #temp t2
      WHERE t2.col1=t1.col1
      ORDER BY t2.col2
      FOR XML PATH('')
    ),1,1,''),',to,',' to ') SerialNumber
FROM (SELECT DISTINCT col1 FROM #temp) t1

DROP TABLE #temp

SQL Server 2017(带有STRING_AGG)的变体:

SELECT
  col1,
  REPLACE(STRING_AGG(outVal,',')WITHIN GROUP(ORDER BY col2),',to,',' to ')
FROM
  (
    SELECT
      col1,
      col2,
      outVal,
      ISNULL(LEAD(outVal)OVER(PARTITION BY col1 ORDER BY col2),'') nextOutVal
    FROM
      (
        SELECT
          col1,
          col2,
          CASE
            WHEN col2-1=LAG(col2)OVER(PARTITION BY col1 ORDER BY col2) AND col2+1=LEAD(col2)OVER(PARTITION BY col1 ORDER BY col2)
            THEN 'to'
            ELSE CAST(col2 AS varchar(10))
          END outVal
        FROM t
      ) q
  ) q
WHERE outVal<>nextOutVal
GROUP BY col1

结果:

col1  SerialNumber
1     1 to 4,6 to 9,11,13
2     3 to 5,7

答案 1 :(得分:1)

解决方案:

使用CTE为每个序列和组串联的开始和结束值的另一种可能方法:

T-SQL:

-- Table creation
CREATE TABLE #ValuesTable (
    Col1 int,
    Col2 int
)
INSERT INTO #ValuesTable VALUES (1, 1)
INSERT INTO #ValuesTable VALUES (1, 2)
INSERT INTO #ValuesTable VALUES (1, 3)
INSERT INTO #ValuesTable VALUES (1, 4)
INSERT INTO #ValuesTable VALUES (1, 6)
INSERT INTO #ValuesTable VALUES (2, 1)
INSERT INTO #ValuesTable VALUES (2, 2)  
INSERT INTO #ValuesTable VALUES (2, 3)
INSERT INTO #ValuesTable VALUES (2, 4)
INSERT INTO #ValuesTable VALUES (2, 6)
INSERT INTO #ValuesTable VALUES (2, 7);
INSERT INTO #ValuesTable VALUES (2, 10);

-- Find sequences
WITH 
TableStart AS (
    SELECT t.Col1, t.Col2, ROW_NUMBER() OVER (ORDER BY t.Col1, t.Col2) AS RN
    FROM #ValuesTable t
    LEFT JOIN #ValuesTable b ON (t.Col1 = b.Col1) AND (t.Col2 = b.Col2 + 1)
    WHERE (b.Col2 IS NULL)
), 
TableEnd AS (
    SELECT t.Col1, t.Col2, ROW_NUMBER() OVER (ORDER BY t.Col1, t.Col2) AS RN
    FROM #ValuesTable t
    LEFT JOIN #ValuesTable b ON (t.Col1 = b.Col1) AND (t.Col2 = b.Col2 - 1)
    WHERE (b.Col2 IS NULL)
), 
TableSequences AS (
    SELECT 
        TableStart.Col1 AS Col1, 
        CASE 
            WHEN (TableStart.Col2 <> TableEnd.Col2) THEN CONVERT(nvarchar(max), TableStart.Col2) + N' to ' + CONVERT(nvarchar(max), TableEnd.Col2)
            ELSE CONVERT(nvarchar(max), TableStart.Col2) 
        END AS Sequence
    FROM TableStart
    LEFT JOIN TableEnd ON (TableStart.RN = TableEnd.RN)
)
-- Select with group concatenation
SELECT
    t1.Col1,
    (
    SELECT t2.Sequence + N', '
    FROM TableSequences t2
    WHERE t2.Col1 = t1.Col1
    ORDER BY t2.Col1
    FOR XML PATH('')
    ) SerialNumber
FROM (SELECT DISTINCT Col1 FROM TableSequences) t1

输出:

Col1    SerialNumber
1       1 to 4, 6, 
2       1 to 4, 6 to 7, 10, 

注释:

在SQL Server 2005、2012、2016上进行了测试。

相关问题