SQL查询以显示表中包含数据的最新行,或者为null

时间:2017-08-25 03:22:57

标签: sql oracle

我有一个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

到目前为止,我能想到的最好的方法是将最旧的行插入临时表,然后在循环中,如果它们存在较新的时间戳,则更新这些值。完成后,使用最新的时间戳更新任何空值。有没有办法可以在不循环并插入临时表的情况下实现这一目标?

2 个答案:

答案 0 :(得分:2)

分析救援功能!按customeridquestionid进行分区,并为每个分区中的行分配row_number()。如果我们不必担心answertext is null,我们只需按created_on desc订购。

为了处理null,我们首先根据answertext是否为空而不是null来排序。这可以通过case表达式轻松完成(见下文)。

然后在外部查询中,我们选择row_number为1的行(在customeridquestionid的每个组合中)。

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