【问题标题】:Merging every two rows of data in a column in SQL Server在 SQL Server 的列中合并每两行数据
【发布时间】:2014-09-27 23:44:51
【问题描述】:

我的表结构是..

Id   UserId EventId
  1      1       A    
  2      1       B
  3      1       C
  4      1       A
  5      1       D

我需要的输出..

UserId   EventStart   EventEnd
1           A           B
1           B           C
1           C           A
1           A           D 

我希望每两行合并成一行,所以如果第一行有 A,第二行有 B,那么结果表的第一行有 A & B..

我已经研究过 PIVOT,但无法弄清楚如何获得我想要的结果..

如果我可以用 sql 解决这个问题会很棒,如果必须在中间层解决,我使用 C#

真诚感谢任何帮助..

谢谢..

【问题讨论】:

  • 请详细说明您的问题。
  • 如何定义 EvntStart 和 EventEnd ???请详细解释...
  • 已编辑问题,请告知是否明确..Tx..
  • SQL 表表示无序集。除非列指定排序,否则表中没有“下一个”行。您的表是否有包含此信息的 id 或创建日期列?
  • 我有一个 ID 和创建日期,我认为它们不是必需的,所以没有添加到结构中..

标签: c# sql sql-server linq linq-to-sql


【解决方案1】:

假设您有一个指定排序的 id 列,您可以使用lead()(在 SQL Server 2012+ 中)获得您想要的:

select userId, eventid as eventstart,
       lead(eventid) over (partition by userid order by id) as eventend
from mytable t;

您正在过滤掉最后一行,这可以通过子查询来完成(where 子句中不允许使用窗口函数):

select t.*
from (select userId, eventid as eventstart,
             lead(eventid) over (partition by userid order by id) as eventend
      from mytable t
     ) t
where eventend is null;

在早期版本的 SQL Server 中,您可以通过其他方式获得相同的效果,例如关联子查询或交叉应用。这是一个例子:

select t.*
from (select userId, eventid as eventstart,
             (select top 1 t2.eventid
              from mytable t2
              where t2.userid = t.userid and
                    t2.id > t.id
              order by t2.id
             ) as eventend
      from mytable t
     ) t
where eventend is not null;

【讨论】:

  • 我在本地有 sql server 2008,但我将托管在 sql azure,为了进行测试,我正在使用相关子查询 - 这里的“我的表名”将替换 t 或 t2?
  • 我认为查询的最后一部分应该是'where eventend is not null;'
  • @Amab 。 . .我完全误读了你的评论。我很抱歉,你是——当然——是正确的。
  • 知道为什么 Or 子句在 where 子句中不起作用。我尝试了 "where eventstart != 'A'" - 这有效,但是当我尝试 "where eventstart != 'A' Or eventstart != 'B'" - 这没有..
  • @Amab 。 . .我不知道你的问题是指什么。但是如果你既不想要 A 也不想要 B,只需使用 not in: eventstart not in ('A', 'B')
【解决方案2】:

一种简单的方法是使用 CTE,在 ID 上生成 Row_Number() 并通过 UserID 和 Rownumber 加入。

declare @t  Table([ID] [int] IDENTITY(1,1) NOT NULL, UserID int,EventID varchar(10))
insert into @t
Select 1,'A'
UNION ALL Select 1,'B'
UNION ALL Select 1,'C'
UNION ALL Select 1,'A'
UNION ALL Select 1,'D'
UNION ALL Select 2,'B'
UNION ALL Select 2,'C'
UNION ALL Select 2,'A'
UNION ALL Select 2,'D'


;With c as
(
Select UserID,EventID,Row_Number() OVER (Order by UserID,ID ) as RN
from @t
)
Select c1.UserID,c1.EventID as EventStart ,c2.EventID as EventEnd
from c c1
Join c c2 on c2.RN=c1.RN+1 and c2.UserID=c1.UserID

【讨论】:

  • 我有 64 个用户的 8462 行数据..,仅用你答案的底部部分,我得到 5084 行更少..
  • 是的,现在我得到的结果与 Gordon-Tx 的答案相同
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 1970-01-01
  • 2011-08-10
  • 2010-12-25
  • 2018-01-12
  • 1970-01-01
相关资源
最近更新 更多