是否可以在SQL Server查询的结果集中“合并”两行?

时间:2011-06-28 16:40:13

标签: sql-server sql-server-2008

我正在查看输出类似以下内容的查询:

Group | Date 1     | Value 1 | Date 2      | Value 2
------+------------+---------+-------------+--------
    A | 2011-06-15 | 105     | NULL        | NULL
    A | NULL       | NULL    | 2011-06-16  | 107
    B | 2011-06-18 | 567     | NULL        | NULL
    B | NULL       | NULL    | 2011-06-20  | 525

我想要的是按小组“扁平化”这些结果 - 有点像行COALESCE

Group | Date 1     | Value 1 | Date 2      | Value 2
------+------------+---------+-------------+--------
    A | 2011-06-15 | 105     | 2011-06-16  | 107
    B | 2011-06-18 | 567     | 2011-06-20  | 525

请注意,每组只会有2行;这不是处理任意数量的数据点,它本质上是一个“前后”查询。

是否可以在次传递中执行此操作? (结果中有大量数据)。这意味着:

  • 没有临时表,表变量或类似的中间步骤(CTE没问题);
  • 加入自身,即在一个查询中获取MINMAX,然后加入这些日期以获取值的明显解决方案。如上所述,这是一个昂贵的查询的结果集,我正在努力不加倍负载。

我知道我可以在技术上用光标做到这一点,但我真的真的不愿意,除非有人能向我证明它比任何基于集合的选项更快。

P.S。请注意,对于组“B”,值2低于值1.我已明确地说明为什么单个GROUP BY采用两个日期的MINMAX和价值不会产生预期的结果。这些值必须与日期相关联。

2 个答案:

答案 0 :(得分:0)

假设你总是在Group中得到对,你可以做GROUP BY [Group],对于4列中的每一列,选择MAX()(基本上取非空值)。

修改:如果您的数据集中包含“Group”,“Date”和“Value”列,并希望合并这些数据集以便您拥有“Group”,“Date 1”, “值1”,“日期2”和“值2”列使用此(第一个CTE代表测试数据):

WITH Results AS (
    SELECT 'A' [Group], CONVERT(datetime, '2011-06-15') [Date], 105 [Value]
    UNION ALL
    SELECT 'A' [Group], CONVERT(datetime, '2011-06-16') [Date], 107 [Value]
    UNION ALL
    SELECT 'B' [Group], CONVERT(datetime, '2011-06-18') [Date], 567 [Value]
    UNION ALL
    SELECT 'B' [Group], CONVERT(datetime, '2011-06-20') [Date], 525 [Value]
),
ResultsIndexed AS (
    SELECT ROW_NUMBER() OVER (PARTITION BY r.[Group] ORDER BY r.[Date]) ix, r.* FROM Results r
)
SELECT r1.[Group], r1.[Date] [Date 1], r1.[Value] [Value 1], r2.[Date] [Date 1], r2.[Value] [Value 1]
    FROM ResultsIndexed r1
    JOIN ResultsIndexed r2 ON (r1.[Group] = r2.[Group]) AND (r2.[ix] = 2)
    WHERE r1.[ix] = 1

答案 1 :(得分:0)

不确定这是否是你想要的。如果你每组只有两行,你可以试试这个。

;WITH cte as
(
    -- You sql output here
    SELECT  *
    FROM    table
)
SELECT  a1.group,a1.date1,a1.value1,a2.date2,a2.value2
FROM    cte a1
INNER JOIN cte a2
 ON a2.date2 IS NOT NULL
 AND a1.group = a2.group
WHERE a1.date1 IS NOT NULL