【问题标题】:SQL query to show most recent row in table with data, or nullSQL 查询以显示表中包含数据的最新行,或为空
【发布时间】:2017-08-25 03:22:56
【问题描述】:

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

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

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    分析函数助你一臂之力!按customeridquestionid 进行分区,并为每个分区中的行分配row_number()。如果我们不必担心answertext is null,我们只需通过created_on desc 订购即可。

    为了处理null,我们首先根据answertext 是否不为空与是否为空来排序。这可以通过 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
    ;
    

    【讨论】:

    • 感谢有关“时间戳”的注释 - 我不得不混淆实际的列名并忘记它是保留字。已在示例中修复。
    【解决方案2】:

    你可以试试:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-10
      • 1970-01-01
      • 2020-08-19
      • 1970-01-01
      • 1970-01-01
      • 2018-07-20
      • 1970-01-01
      • 2013-12-10
      相关资源
      最近更新 更多