我有一个Oracle DB表结构,其中的行通过面试过程填充,每个“客户”可以多次完成面试过程,即使是在同一天。表结构如下所示:
Table: Customers
-------------
CustomerId
...
Table: Questions
-------------
QuestionId | QuestionText
0 | Last Location?
1 | Last Color?
2 | Last Food?
3 | Last Drink?
Table: Answers
-------------
Id | CustomerId | QuestionId | AnswerText | Created_On
1 0 0 Chicago 08/15/2017 7:56:34 AM
2 0 0 Laramie 08/16/2017 9:27:23 AM
3 0 0 Null 08/17/2017 6:34:56 AM
4 0 1 Null 08/15/2017 7:56:34 AM
5 0 1 Green 08/16/2017 9:27:23 AM
6 0 1 Blue 08/17/2017 6:34:56 AM
7 0 2 Pizza 08/15/2017 7:56:34 AM
8 0 2 Null 08/16/2017 9:27:23 AM
9 0 2 Null 08/17/2017 6:34:56 AM
10 0 3 Null 08/15/2017 7:56:34 AM
11 0 3 Null 08/16/2017 9:27:23 AM
12 0 3 Null 08/17/2017 6:34:56 AM
目前,我们通过查询每个问题的最新时间戳数据并显示结果来显示“最后一次采访”,无论是有值还是为空,如下所示:
LastAnswer_QueryResult
-------------
Id | CustomerId | QuestionId | AnswerText | Created_On
3 0 0 Null 08/17/2017 6:34:56 AM
6 0 1 Blue 08/17/2017 6:34:56 AM
9 0 2 Null 08/17/2017 6:34:56 AM
12 0 3 Null 08/17/2017 6:34:56 AM
新要求是使用值显示每个问题的最新答案,如果问题从未得到回答,则为null。如果我能得到正确的查询,上面的示例数据的结果将如下所示:
MostRecentAnswer_QueryResult
Id | CustomerId | QuestionId | AnswerText | Created_On
2 0 0 Laramie 08/16/2017 9:27:23 AM
6 0 1 Blue 08/17/2017 6:34:56 AM
7 0 2 Pizza 08/15/2017 7:56:34 AM
12 0 3 Null 08/17/2017 6:34:56 AM
到目前为止,我能想到的最好的方法是将最旧的行插入临时表,然后在循环中,如果它们存在较新的时间戳,则更新这些值。完成后,使用最新的时间戳更新任何空值。有没有办法可以在不循环并插入临时表的情况下实现这一目标?
答案 0 :(得分:2)
分析救援功能!按customerid
和questionid
进行分区,并为每个分区中的行分配row_number()
。如果我们不必担心answertext is null
,我们只需按created_on desc
订购。
为了处理null
,我们首先根据answertext
是否为空而不是null来排序。这可以通过case
表达式轻松完成(见下文)。
然后在外部查询中,我们选择row_number
为1的行(在customerid
和questionid
的每个组合中)。
select id, customerid, questionid, answertext, ts
from (
select id, customerid, questionid, answertext, ts,
row_number() over ( partition by customerid, questionid
order by case when answertext is not null
then 0 end,
created_on desc
) as rn
from answers
)
where rn = 1
;
答案 1 :(得分:0)
您可以尝试:
select MAX(a.id) ID, a.CustomerId , q.QuestionId,LISTAGG(AnswerText,' * ') WITHIN GROUP (ORDER BY ID) AnswerText, max(a.Created_On) Created_On
from Questions q
left join Answers a
on a.QuestionId = q.QuestionId
where a.AnswerText is not null
group by a.CustomerId , q.QuestionId
UNION ALL
select MAX(a.id) ID, a.CustomerId , q.QuestionId ,LISTAGG(AnswerText,' *') WITHIN GROUP (ORDER BY ID) AnswerText, max(a.Created_On) Created_On
from Questions q
left join Answers a
on a.QuestionId = q.QuestionId
where a.AnswerText is null AND
Q.QuestionId NOT IN(
select q.QuestionId
from Questions q
left join Answers a
on a.QuestionId = q.QuestionId
where a.AnswerText is not null
group by a.CustomerId , q.QuestionId
)
group by a.CustomerId , q.QuestionId
ORDER BY QuestionId
之后,您将在' *'
之间获得第一个名称AnswerText