0

我有一个数据库问题,我目前无法用简单的解决方案解决这个问题。在我的数据库中,我有一个存储事件值的表。0 和 1 带有时间戳。问题是同一事件可能作为业务规则发生两次。像下面

  • '2008-09-22 16:28:14.133', 0
  • '2008-09-22 16:28:35.233', 1
  • '2008-09-22 16:29:16.353', 1
  • '2008-09-22 16:31:37.273', 0
  • '2008-09-22 16:35:43.134', 0
  • '2008-09-22 16:36:39.633', 1
  • '2008-09-22 16:41:40.733', 0

在现实生活中,这些事件是循环的,我试图查询以获取这些事件的循环,但我需要忽略重复值( 1,1 )当前的解决方案是使用 SQL 游标循环每个并抛出值如果以前是一样的。我考虑过在插入时使用触发器来清理后处理表,但我想不出一个简单的解决方案来基于这个集合。

有什么想法或建议吗?

谢谢

4

4 回答 4

1

(前言.......我只在oracle中做过这个,但我很确定数据库是否支持触发器这一切都是可能的)

有一个插入前触发器,它选择具有最大时间戳值的行。如果该行的值与您要插入的值相同,请忽略它。

这应该使它们都处于正确的状态。

现在,如果您需要存储两组状态,则触发器始终可以在全包表上插入,但仅在值更改时才在“过滤”表上进行查找和插入。

于 2008-09-22T20:53:20.807 回答
0

只是为了让我理解这个问题。

如果您根据时间戳对行集进行排序,有时会出现相邻的重复值,例如上述第 2 项和第 3 项中的一对 1?然后你在第 4 和第 5 有双 0,是这样吗?

并且您想要对应对中的最后一个(或序列,如果有超过 2 个)?

为什么需要删除它们?我之所以问是因为除非它们在此表的大小中占据很大份额,否则当您需要处理或显示它们时,可能更容易像按顺序一样将它们过滤掉。

一种解决方案,虽然不是一个很好的解决方案,但将检索高于您正在检查的当前行的时间戳的最小时间戳然后从中检索值,如果相同,则不要返回当前行.

这是获取所有内容的 SQL:

SELECT timestamp, value
FROM yourtable

以下是如何加入以获得高于当前时间戳的最小时间戳:

SELECT T1.timestamp, MIN(T2.timestamp) AS next_timestamp, T1.value
FROM yourtable T1, yourtable T2
WHERE T2.timestamp > T1.timestamp
GROUP BY T1.timestamp, T1.value

(我担心上面的查询会非常慢)

然后检索与该最小时间戳对应的值

SELECT T3.timestamp, T3.value
FROM (
    SELECT T1.timestamp, MIN(T2.timestamp) AS next_timestamp, T1.value
    FROM yourtable T1, yourtable T2
    WHERE T2.timestamp > T1.timestamp
    GROUP BY T1.timestamp, T1.value
) T3, yourtable AS T4
WHERE T3.next_timestamp = T4.timestamp
  AND T3.value <> T4.value

不幸的是,这不会产生最后一个值,因为它需要一个后续值来比较。一个简单的虚拟哨兵值(如果需要,您可以将其合并)将处理该问题。

这是我测试上述查询的 sqlite 数据库转储:

BEGIN TRANSACTION;
CREATE TABLE yourtable (timestamp datetime, value int);
INSERT INTO "yourtable" VALUES('2008-09-22 16:28:14.133',0);
INSERT INTO "yourtable" VALUES('2008-09-22 16:28:35.233',1);
INSERT INTO "yourtable" VALUES('2008-09-22 16:29:16.353',1);
INSERT INTO "yourtable" VALUES('2008-09-22 16:31:37.273',0);
INSERT INTO "yourtable" VALUES('2008-09-22 16:35:43.134',0);
INSERT INTO "yourtable" VALUES('2008-09-22 16:36:39.633',1);
INSERT INTO "yourtable" VALUES('2008-09-22 16:41:40.733',0);
INSERT INTO "yourtable" VALUES('2099-12-31 23:59:59.999',2);
COMMIT;

这是(格式化的)输出:

timestamp                 value
2008-09-22 16:28:14.133   0
2008-09-22 16:29:16.353   1
2008-09-22 16:35:43.134   0
2008-09-22 16:36:39.633   1
2008-09-22 16:41:40.733   0
于 2008-09-22T20:55:12.253 回答
0

这个问题实际上是一个数据捕获问题。典型的数据库引擎不是解决它的好选择。一个简单的预处理器应该检测输入数据集的变化并只存储相关数据(时间戳等)。

一个简单的解决方案是在数据库环境中(例如在 Oracle 中)创建一个包,该包可以具有本地内存变量,用于存储最后输入的数据集并消除不需要的数据库访问。

当然,您可以使用数据库环境的所有功能来定义“输入数据集的变化”并存储过滤后的数据。因此,它可能很简单,也可能很复杂,如您所愿。

于 2008-09-22T21:08:41.597 回答
0

这使用 SQL Server 公用表表达式,但它可以内联,表 t 具有列 dt 和循环状态:

;WITH Firsts AS (
    SELECT t1.dt
        ,MIN(t2.dt) AS Prevdt
    FROM t AS t1
    INNER JOIN t AS t2
        ON t1.dt < t2.dt
        AND t2.cyclestate <> t1.cyclestate
    GROUP BY t1.dt
)
SELECT MIN(t1.dt) AS dt_start
    ,t2.dt AS dt_end
FROM t AS t1
INNER JOIN Firsts
    ON t1.dt = Firsts.dt
INNER JOIN t AS t2
    ON t2.dt = Firsts.Prevdt
    AND t1.cyclestate <> t2.cyclestate
GROUP BY t2.dt
    ,t2.cyclestate
HAVING MIN(t1.cyclestate) = 0
于 2008-09-22T21:12:05.677 回答