【问题标题】:SQLITE query, if last row matches criteria, check row preceding it matches different criteriaSQLITE 查询,如果最后一行匹配条件,则检查它前面的行是否匹配不同的条件
【发布时间】:2013-07-27 09:43:09
【问题描述】:

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

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

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

一切都将按 Fruit 排序,然后是 Date。

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

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

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

编辑:

这是我最后用的,挺慢的,但是如果我索引Date,还不错:

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 缓存了结果。

【问题讨论】:

  • 为什么你认为桌子有一个内在的顺序? SQL 的第一条规则是表行只具有 您的查询 告诉它们的顺序。
  • 我要按日期订购,我没有说得特别清楚。我已经重新措辞了。

标签: sqlite


【解决方案1】:

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'

An SQLfiddle to test with.

【讨论】:

  • 似乎工作得很好,谢谢。似乎也很快。我还在测试它,我的实际数据库并不像上面的那么简单,但希望我能够适应我的需要。
  • 不幸的是,在我的实际数据库中,我的条目具有相同的日期,因此我使用 Id(这是一个自动递增字段)来检查订单。但是如果我检查 Id 而不是 Date,这真的很慢。我想知道使用 GROUP BY 并以某种方式浏览最后一行和倒数第二行是否会更快?这是我首先尝试的方法,但我无法弄清楚。如果我想出一个更有效的查询,我会在这里发布。这是一个很好的起点。
  • 在显示这些条目已排序的其他查询中,我使用 Date 和 Id 作为我的 ORDER BY,因为我更喜欢日期而不是它添加到数据库的顺序。如果我在订购之前将日期和 ID 连接起来,这会更快,但似乎是解决速度问题的一种很奇怪的方法,我相信一定有更好的方法。
  • @user989266 如果 date 很快,id 很慢,这听起来像是索引问题。你有id的索引吗? Date 上有任何现有索引吗?
  • 嗨,索引 Date 加快了速度,因为仅按 Date 排序非常快,我认为我不需要索引它。但事实证明这是主要的瓶颈。
【解决方案2】:

我将表命名为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'

【讨论】:

  • 您好,这非常有效,但是当两条记录具有相同的日期时,会导致我的数据库出现问题。我也想按 Id 排序,其中 Id 是一个自动递增字段。例如。如果有 2 个日期相同,我想选择 ID 较高的那个。您知道我如何将其合并到此查询中吗?我真的应该在最初的问题中提到 Id,但没有意识到调整它以适应我的数据库会很困难。
  • 我尝试了考虑 ID 的新查询,但如果所有日期设置相同,则查询不会返回任何内容。我做了一个 SQL Fiddle 来尝试一下:sqlfiddle.com/#!7/3bb0e/2。这是一个非常棘手的问题。 :\
猜你喜欢
  • 2011-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 2015-10-31
  • 1970-01-01
  • 2018-01-10
  • 1970-01-01
相关资源
最近更新 更多