从对话开始和结束之间的范围中选择数据(使用 SQL / H2 数据库进行聊天日志分析)

Posted

技术标签:

【中文标题】从对话开始和结束之间的范围中选择数据(使用 SQL / H2 数据库进行聊天日志分析)【英文标题】:Select data from range between conversational openings and closings (chat log analysis using SQL / H2 Database) 【发布时间】:2017-09-12 14:43:44 【问题描述】:

我有一个名为“conversations”的表,它包含如下数据:

 TIMESTAMP       | ACTOR| CONTEXT| MESSAGE    | CLASSIFICATION
-----------------+------+--------+------------+-----------
01.02.2015 09:38 | user | text   | blablabla  | normal
01.02.2015 09:46 | bot  | text   | blablabla  | normal
01.02.2015 10:19 | user | text   | hi bot!    | opening
01.02.2015 10:20 | bot  | text   | blablabla  | normal
01.02.2015 10:21 | user | text   | blablabla  | normal
01.02.2015 10:22 | bot  | text   | blablabla  | normal
01.02.2015 10:23 | user | text   | ok bye bot | closing
01.02.2015 11:53 | bot  | text   | blablabla  | normal
01.02.2015 12:14 | user | text   | goodbye    | closing
01.02.2015 12:33 | bot  | text   | blablabla  | normal
01.02.2015 12:51 | bot  | text   | blablabla  | normal

我想SELECT 是我的数据集中的“开头”和“结尾”之间的范围,以便将成功构建的对话与所有其他用户输入/机器人输出分开。

预期的输出是:

 TIMESTAMP       | ACTOR| CONTEXT| MESSAGE    | CLASSIFICATION
-----------------+------+--------+------------+-----------
01.02.2015 10:19 | user | text   | hi bot!    | opening
01.02.2015 10:20 | bot  | text   | blablabla  | normal
01.02.2015 10:21 | user | text   | blablabla  | normal
01.02.2015 10:22 | bot  | text   | blablabla  | normal
01.02.2015 10:23 | user | text   | ok bye bot | closing

-----------更新

我执行了cmets中提出的查询,但是H2没有输出任何数据:

Output_Info

谢谢!

【问题讨论】:

请包括您的预期输出。 当然。我刚刚编辑了最初的帖子。 【参考方案1】:
select * 
from
    (select
        t.*,
        case when @rangeStarted=1 then 1 else 0 end as inside_range,
        @rangeStarted:=case 
                         when CLASSIFICATION='opening' then 1
                         when CLASSIFICATION='normal' then @rangeStarted
                         when CLASSIFICATION='closing' then 0
                       end 
    from t, (select @rangeStarted:=0)
    order by TIMESTAMP) sub
where inside_range=1

我们根据行定义一个变量(最初为 0)。当我们遇到 'opening' 时该变量设置为 1,并在遇到 'closeing' 时重置回 0。

然后只留下变量为1的记录

更新:放置在带有排序的子查询逻辑中

更新 2:

select
        t.*,
        case when @rangeStarted=1 OR CLASSIFICATION='opening' then 1 else 0 end as inside_range,
        @rangeStarted:=case 
                         when CLASSIFICATION='opening' then 1
                         when CLASSIFICATION='normal' then @rangeStarted
                         when CLASSIFICATION='closing' then 0
                       end  as r
from Table1 t, (select @rangeStarted:=0) as var
order by TIMESTAMP

在 Juan Carlos Oropeza 提供的测试中校正和测试内部范围

【讨论】:

case when @rangeStarted=0 then 1 else 0 end, 行是什么?您似乎没有使用它或分配别名 更新了逻辑。错误放置的别名。表达式填充该字段。如果行变量@rangeStarted 是 1 我们在范围内 好吧,现在明白了;) 我认为你应该使用子查询,因为你需要添加ORDER BY TIMESTAMP否则你不能保证顺序。 更新为包含按逻辑排序【参考方案2】:

为了解决这个问题,我想你是一个日期,你需要在左括号和右括号之间,所以:

(OPEN   date   CLOSE)

从这里你有:date >= OPEN and date <= CLOSE

但是对于这种情况:OPEN date1 CLOSE date2 CLOSE

您需要检查 date2 是否有 Open without close:nearLeftOpen > nearLeftClose

所以最后的逻辑变成了:

SQL DEMO:

SELECT t1.*
FROM Table1 t1
WHERE t1.TIMESTAMP >= (SELECT MAX(IF (CLASSIFICATION='opening', TIMESTAMP, null))
                       FROM Table1 t2
                       WHERE t2.TIMESTAMP <= t1.TIMESTAMP)
  AND t1.TIMESTAMP <= (SELECT MIN(IF (CLASSIFICATION='closing', TIMESTAMP, null))
                       FROM Table1 t3
                       WHERE t3.TIMESTAMP >= t1.TIMESTAMP)      
  AND (SELECT MAX(IF (CLASSIFICATION='opening', TIMESTAMP, null))
       FROM Table1 t2
       WHERE t2.TIMESTAMP <= t1.TIMESTAMP) > 
      (SELECT MAX(IF (CLASSIFICATION='closing', TIMESTAMP, '1900-01-01'))
       FROM Table1 t3
       WHERE t3.TIMESTAMP < t1.TIMESTAMP)

输出

如您所见,我将一个法线更改为打开并且也出现了。根据您的数据,我不知道您想如何处理这些。由您决定是否为边境案件提供足够的信息,以便我们知道如何处理这些案件。

这可以解决添加另一个条件反转最后一个条件以确保关闭之前没有任何其他打开。

此代码仍需要针对其他情况进行进一步测试。

【讨论】:

以上是关于从对话开始和结束之间的范围中选择数据(使用 SQL / H2 数据库进行聊天日志分析)的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 仅在月份和年份之间选择数据

第四十三章 SQL函数 DATEDIFF

用于选择开始和结束日期的数据范围选择器

记录之间的 SQL Server 日期时间范围

从sql server获取两个日期之间的数据

SQL - 选择两个字符串行之间的所有行