在运行时在sql数据库中过滤出重复值-基于set

时间:2020-03-06 14:33:51  来源:igfitidea点击:

我有一个数据库问题,目前无法通过简单的解决方案来解决。在我的数据库中,我有一个表来存储事件值。带有时间戳的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游标来循环每个值,如果以前是一样的。香港专业教育学院考虑在触发器上使用触发器来清理后处理表中,但我不能想到一个简单的解决方案基于此设置。

有什么想法或者建议吗?

谢谢

解决方案

(前言.......我只在oracle中完成了此操作,但是我很确定数据库是否支持触发器是有可能的)

有一个插入前触发器,用于选择具有最大时间戳值的行。如果该行的值与我们要插入的行的值相同,则将其忽略。

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

现在,如果我们需要同时存储两组状态,则触发器可以始终插入全包表中,但是仅当值更改时才执行查找并插入"已过滤"表中。

以便我了解问题。

如果我们根据时间戳对行集进行排序,有时会出现重复的值,例如上面第二对和第三项中的一对1?然后在第4个和第5个中有双0,是吗?

我们是否想要对应对中的最后一个(如果有两个以上,则为序列)?

为什么需要删除它们?我之所以问是因为,除非它们占据该表的很大一部分,否则当我们需要处理或者显示它们时,就像按顺序进行操作一样,将它们过滤掉可能会更容易。

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

这是获取所有内容的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

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

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

当然,我们可以使用数据库环境的所有功能来定义"输入数据集的更改"并存储过滤后的数据。因此,随心所欲可能很容易,也可能很复杂。

它使用SQL Server公用表表达式,但可以内联,表t的列为dt和cyclestate:

;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