0

我发现很难解决这个问题,而且我在任何地方都找不到这个特定问题的任何答案:

假设我有一张这样的桌子,我只是以水果为例:

Fruit | Date | Value
=================================
Apple |    1 | other_random_value
Apple |    2 | some_value_1
Apple |    3 | some_value_2
Pear  |    1 | other_random_value
Pear  |    2 | unexpected_value_1
Pear  |    3 | some_value_2

一切都将由水果订购,然后是日期。

基本上,如果最后一行(对于每个水果)是 some_value_2,但前面的不是 some_value_1,我只想匹配那些水果(即在本例中为梨)。

所以,some_value_2 我总是希望在某个特定水果的某个值之后出现,如果不是,我想针对这些特定水果标记错误。匹配 some_value_2 之前没有任何内容的情况也很好,但如果这太复杂,我可以单独匹配它并检查 some_value_2 不是第一行,我不认为这将是一个困难的查询。

编辑:此外,能够匹配前面值意外的任何连续行会很好,尽管我主要关心最后两行。因此,如果能够匹配所有连续的行会产生更简单且性能更好的查询,那么我可能会这样做。我将同时进行 INSERT(到警报表中),所以如果我可以将它标记为 ERROR(如果它是最后两行),如果它不是 WARNING,那将非常漂亮。虽然我不知道从哪里开始编写执行此操作的查询。还必须有一个执行良好的查询,因为我将在一个大型数据集中使用它。

编辑:

这是我最后使用的,它很慢,但如果我索引日期,它还不错:

SELECT c.Id AS CId, c.Fruit AS CFruit,
       c.Date AS CDate, c.Value AS CValue,
       (SELECT Id
        FROM fruits
        WHERE Fruit = c.Fruit
        AND Date >= c.Date
        AND Id > c.Id
        ORDER BY Date, Id) AS NId, n.Fruit AS NFruit,
       n.Date AS NDate, n.Value AS NValue
FROM fruits AS c
JOIN fruits AS n ON n.Id = NId
ORDER BY c.Date, c.Id

我可能会在某个时候再次尝试 Joachim 的方法,因为我意识到我得到了很多我并不真正关心的结果。或者我什至可以尝试以某种方式合并两者并酌情委托给 INFO/ERROR ......


已解决:我使用了与获取 NId 相同的 SELECT 语句,并使用了 SELECT COUNT(*) 而不是 SELECT Id。这告诉我当前结果之后的结果数量。然后我只是使用 CASE 运算符将其转换为一个名为 Latest 的布尔字段 :)。所以我有效地结合了 Nicolas 和 Joachim 的方法。性能似乎还不错,可能是因为 SQLite 缓存了结果。

4

2 回答 2

0

SQLite(据我所知)在这方面的高效运算符有点低,所以这是我现在能想到的最好的:)

SELECT Fruit FROM fruits
WHERE ( SELECT COUNT(*) FROM fruits f 
        WHERE f.fruit=fruits.fruit 
          AND f.date > fruits.date ) = 1
  AND fruits.value <> 'some_value_1'
INTERSECT 
SELECT Fruit FROM fruits
WHERE ( SELECT COUNT(*) FROM fruits f 
        WHERE f.fruit=fruits.fruit 
          AND f.date > fruits.date ) = 0
  AND fruits.value = 'some_value_2'

一个用于测试的 SQLfiddle

于 2013-07-27T11:13:11.197 回答
0

我命名了表fruits。此查询为您获取“关键”的前一个日期(水果 + 日期)

select fruit, date, value currvalue,
      (select max(date) precedingDate 
         from fruits p 
         where p.fruit = c.fruit 
         and p.date < c.date) precedingdate 
 from fruits c ;

从那里我们可以得到每个键的先验值

select f1.*, precedingdate, f2.value precedingvalue
from
    fruits f1 join
    (select fruit, date, value,
          (select max(date) precedingDate 
             from fruits p 
             where p.fruit = c.fruit 
             and p.date < c.date) precedingdate 
     from fruits c) f2 
   on f1.fruit = f2.fruit and f1.date = precedingdate ;

对于具有前一行的所有行,您将获得当前和前一个日期以及当前和前一个值。

编辑:当有几个相同的先前日期时,我们添加一个用于选择的 id(见下面的评论)

为了清楚起见,我将使用中间视图,但您可以编写一个大查询。

和以前一样,上一个日期是什么:

create view VFruitsWithPreviousDate
as select fruit, date, value, id,
 (select max(date) 
         from fruits p 
         where p.fruit = c.fruit 
         and p.date < c.date) previousdate 
 from fruits c  ;

以前的 id 是什么:

create view  VFruitsWithPreviousId
as select fruit, date, value, 
    (select max(id) 
    from fruits f
    where v.fruit = f.fruit AND 
       v.previousdate = f.date) previousID
from VFruitsWithPreviousDate v ;

对所有连续行的查询:

select f.*, v.value
from fruits f
join VFruitsWithPreviousId v on  f.id = v.previousid ;

然后您可以添加条件WHERE f.Value = 'some_value_2' AND v.value != 'some_value_1'

于 2013-07-27T14:54:34.323 回答