将行转换为允许重复的列

发布于 2024-09-17 13:59:55 字数 1591 浏览 7 评论 0原文

考虑下面的表和行:

清单 A。

ID, name, event, type
1, 'John Doe', '2010-09-01 15:00:00.000', 'input'
1, 'John Doe', '2010-09-03 11:00:00.000', 'input'
1, 'John Doe', '2010-09-04 17:00:00.000', 'input'
1, 'John Doe', '2010-09-02 15:00:00.000', 'output'
1, 'John Doe', '2010-09-03 16:00:00.000', 'output'
1, 'John Doe', '2010-09-06 17:00:00.000', 'output'

我想要的是将行转换为列,这样我就可以有两个不同的列:输入事件和输出事件。像:

清单 B.

ID, name, input event, output event
1, 'John Doe', '2010-09-01 15:00:00.000', '2010-09-02 15:00:00.000'
1, 'John Doe', '2010-09-03 11:00:00.000', '2010-09-03 16:00:00.000'
1, 'John Doe', '2010-09-04 17:00:00.000', '2010-09-06 17:00:00.000'

我能够得到类似以下的内容:

清单 C.

ID, name, input event, output event
1, 'John Doe', '2010-09-01 15:00:00.000', null
1, 'John Doe', '2010-09-03 11:00:00.000', null
1, 'John Doe', '2010-09-04 17:00:00.000', null
1, 'John Doe', null, '2010-09-02 15:00:00.000'
1, 'John Doe', null, '2010-09-03 16:00:00.000'
1, 'John Doe', null, '2010-09-06 17:00:00.000'

,但问题是如何展平行,因为重复的元组 ID-name 是相关的。要将行转换为列,我通常编写如下代码:

select ID, name, max(case when type = 'input' then event else null end) as 'input event', max(case when type = 'output' then event else null end) as 'output event' from events group by ID, name

,但是当然,GROUP BY 会忽略重复项,这就是我不想要的。

有什么想法如何通过查询来实现这一点吗?

如果有一个可移植的 sql 解决方案或 postgresql 就太好了,但任何想法都值得赞赏。

编辑:抱歉回复晚了。 AlexRednic 和 Mark Ba​​nnister 的两个解决方案都实现了我想要的。我最终选择了第二个,因为它对我来说看起来更清晰。谢谢大家的回答!

Consider the following table and rows:

Listing A.

ID, name, event, type
1, 'John Doe', '2010-09-01 15:00:00.000', 'input'
1, 'John Doe', '2010-09-03 11:00:00.000', 'input'
1, 'John Doe', '2010-09-04 17:00:00.000', 'input'
1, 'John Doe', '2010-09-02 15:00:00.000', 'output'
1, 'John Doe', '2010-09-03 16:00:00.000', 'output'
1, 'John Doe', '2010-09-06 17:00:00.000', 'output'

What I want is to convert rows into columns, so I can have two different columns, input event and output event. Like:

Listing B.

ID, name, input event, output event
1, 'John Doe', '2010-09-01 15:00:00.000', '2010-09-02 15:00:00.000'
1, 'John Doe', '2010-09-03 11:00:00.000', '2010-09-03 16:00:00.000'
1, 'John Doe', '2010-09-04 17:00:00.000', '2010-09-06 17:00:00.000'

I was able to get something like following:

Listing C.

ID, name, input event, output event
1, 'John Doe', '2010-09-01 15:00:00.000', null
1, 'John Doe', '2010-09-03 11:00:00.000', null
1, 'John Doe', '2010-09-04 17:00:00.000', null
1, 'John Doe', null, '2010-09-02 15:00:00.000'
1, 'John Doe', null, '2010-09-03 16:00:00.000'
1, 'John Doe', null, '2010-09-06 17:00:00.000'

, but the problem is how to flat the rows, since the duplicate tuples ID-name ARE relevant. To convert rows into columns I usually code something like this:

select ID, name, max(case when type = 'input' then event else null end) as 'input event', max(case when type = 'output' then event else null end) as 'output event' from events group by ID, name

, but of course, the GROUP BY is going to leave out the duplicates, and that's what I don't want.

Any ideas how to achieve that with a query?

It would be nice to have a portable sql solution or for postgresql, but any idea is much appreciated.

EDIT: sorry for late answer. Both solutions from AlexRednic and Mark Bannister accomplish what I wanted. I finally opted for the second one, since it looks clearer to me. Thanks all for your answers!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

廻憶裏菂餘溫 2024-09-24 14:02:38

我从头开始写:

create table #a(
ID int,
name varchar(30),
event datetime,
type varchar(10)
)

insert #a
select  
1, 'John Doe', '2010-09-01 15:00:00.000', 'input'
union select 1, 'John Doe', '2010-09-01 16:00:00.000', 'input'
union select 1, 'John Doe', '2010-09-01 17:00:00.000', 'input'
union select 1, 'John Doe', '2010-09-02 15:00:00.000', 'output'
union select 1, 'John Doe', '2010-09-02 16:00:00.000', 'output'
union select 1, 'John Doe', '2010-09-02 17:00:00.000', 'output'

--这是解决方案sql

select 
    ID, 
    name, 
    case when type = 'input' then event else null end "input event",
    case when type = 'output' then event else null end "output event"
 from #a

I'm writing from the beginning:

create table #a(
ID int,
name varchar(30),
event datetime,
type varchar(10)
)

insert #a
select  
1, 'John Doe', '2010-09-01 15:00:00.000', 'input'
union select 1, 'John Doe', '2010-09-01 16:00:00.000', 'input'
union select 1, 'John Doe', '2010-09-01 17:00:00.000', 'input'
union select 1, 'John Doe', '2010-09-02 15:00:00.000', 'output'
union select 1, 'John Doe', '2010-09-02 16:00:00.000', 'output'
union select 1, 'John Doe', '2010-09-02 17:00:00.000', 'output'

-- here is the solution sql

select 
    ID, 
    name, 
    case when type = 'input' then event else null end "input event",
    case when type = 'output' then event else null end "output event"
 from #a
离去的眼神 2024-09-24 14:02:10
select t1.id,t1.name,t1.event,t2.event from test t1
    inner join test t2 on t1.event <= t2.event 
        and t1.type = 'input' 
        and t2.type = 'output'
                   and t1.id = t2.id
                   and t1.name = t2.name

问题是您需要以某种方式链接输入/输出会话。在此查询中,我通过使用时间戳事件列来完成此操作。如果这不是您想要的,您能否提供更多信息?

更新:现在,您可以做一些后处理

with a as
(
select t1.id,t1.name,t1.event as in_event,t2.event as out_event from test t1
    inner join test t2 on t1.event <= t2.event 
                   and t1.type = 'input' 
                   and t2.type = 'output'
                   and t1.id = t2.id
                   and t1.name = t2.name
)
select id,name,in_event,min(out_event)
       from a
group by id,name,in_event
select t1.id,t1.name,t1.event,t2.event from test t1
    inner join test t2 on t1.event <= t2.event 
        and t1.type = 'input' 
        and t2.type = 'output'
                   and t1.id = t2.id
                   and t1.name = t2.name

The thing is you need somehow to link the input/output sessions. In this query I did it by using the timestamp event column. Could you provide more information if this isn't what you wanted?

Update: now, to post-process a bit you could do

with a as
(
select t1.id,t1.name,t1.event as in_event,t2.event as out_event from test t1
    inner join test t2 on t1.event <= t2.event 
                   and t1.type = 'input' 
                   and t2.type = 'output'
                   and t1.id = t2.id
                   and t1.name = t2.name
)
select id,name,in_event,min(out_event)
       from a
group by id,name,in_event
甚是思念 2024-09-24 14:01:45

请尝试以下操作:

select ID, name, event as 'input event', 
       (select min(o.event) 
        from events o 
        where o.type = 'output' and 
              i.ID = o.ID and 
              i.name = o.name and 
              i.event < o.event) as 'output event' 
from events i
where i.type = 'input'
group by ID, name, event

Try the following:

select ID, name, event as 'input event', 
       (select min(o.event) 
        from events o 
        where o.type = 'output' and 
              i.ID = o.ID and 
              i.name = o.name and 
              i.event < o.event) as 'output event' 
from events i
where i.type = 'input'
group by ID, name, event
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文