2013-07-27 4 views
0

Мне трудно понять эту проблему, и я не мог найти ответы на эту конкретную проблему в любом месте:SQLITE-запрос, если последняя строка соответствует критериям, проверка строки, предшествующей ему, соответствует различным критериям (RESOLVED)

Скажем, у меня есть таблица, как это, я просто использовать фрукты в качестве примера:

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, я хочу совместить именно эти плоды (т. Е. В этом случае, Pear).

Итак, some_value_2 Я всегда ожидаю, что придет после строки с определенным значением для этого конкретного фрукта, и если это не так, я хочу помечать ошибки против этих конкретных фруктов. Также было бы неплохо сопоставить случаи, когда ничего не предшествует some_value_2, хотя, если это слишком сложно, я мог бы сопоставить его отдельно и просто проверить, что some_value_2 не является первой строкой, которую я не думаю, будет сложным запросом.

EDIT: Кроме того, быть в состоянии сопоставить любые последовательные строки, где предыдущее значение является неожиданным, было бы неплохо, хотя я в основном забочусь о последних двух строках. Поэтому, если возможность сопоставления всех последовательных строк приводит к более простому и эффективному запросу, я могу пойти с этим. Я буду делать INSERT в одно и то же время (в таблице предупреждений), поэтому, если бы я мог обозначить его как ОШИБКУ, если это последние две строки и ПРЕДУПРЕЖДЕНИЕ, если это не так, это будет действительно изящно. Хотя я не знаю, с чего начать писать запрос, который делает это. Кроме того, наличие запроса, который хорошо работает, является обязательным, поскольку я буду использовать это через большой набор данных.

Любые идеи?

EDIT:

Это то, что я в конце концов, это довольно медленно, но если индекс 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 

Я мог бы попробовать метод Иоахима снова в какой-то момент, когда я понял, что получаю много результатов, о которых я не очень люблю. Или я мог бы даже попробовать включения двух-то и делегировать INFO/ERROR в зависимости от обстоятельств ...

EDIT: Я использовал тот же SELECT, заявление, что я использовал, чтобы получить НДИ, и использовать SELECT COUNT (*) вместо SELECT Id. Это сказало мне количество результатов после текущего. Затем я просто использовал оператор CASE, чтобы превратить его в логическое поле, называемое последним :). Поэтому я эффективно сочетал методы Николаса и Йоахима. Производительность по-прежнему кажется ОК, вероятно, потому что SQLite кэширует результаты. Спасибо всем :)

+0

Почему вы предполагаете, что в таблице есть неотъемлемый порядок? Первое правило SQL состоит в том, что строки таблицы имеют только такой порядок, как ваш запрос_ говорит им. –

+0

Я собираюсь заказать по дате, я не делал этого особенно ясно. Я переформулировал это. – user989266

ответ

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' 

An SQLfiddle to test with.

+0

Кажется, отлично работает, спасибо. Также кажется быстрым. Я все еще проверяю его, моя фактическая база данных не такая простая, как выше, но, надеюсь, я смогу адаптировать ее к моим потребностям. – user989266

+0

К сожалению, в моей фактической базе данных у меня есть записи, имеющие одну и ту же дату, поэтому я использую Id (который является полем автоматического увеличения), чтобы также проверить порядок. Но это очень медленно, если я проверяю Id, а не Date. Интересно, может ли использование GROUP BY и каким-то образом скрининг последних и вторых строк последним? Это был подход, который я пытался сначала, но я не мог понять это. Если я выясню более эффективный запрос, я отправлю его здесь. Это хорошая отправная точка. – user989266

+0

В других запросах, где я показываю эти записи отсортированы, я использую Date и Id как мой ORDER BY, потому что я одобряю дату над порядком, который был добавлен в базу данных. Если я конкатенирую дату и идентификатор, прежде чем я его закажу, это будет быстрее, но, похоже, это довольно странный способ обойти проблему скорости, я уверен, что должен быть лучший способ. – user989266

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 ; 

Для всех строк, которые имеют предыдущие строка, вы получаете как текущую, так и предыдущую дату и текущее и предыдущее значение.

Edit: мы добавим идентификатор, используемый для выбора, когда есть несколько идентичны предыдущей даты (см комментарии ниже)

Я буду использовать промежуточные взгляды ради ясности, но вы можете написать один большой запрос.

Как и прежде, в чем предыдущая дата:

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'

+0

Привет, это работает очень хорошо, но вызывает проблемы в моей базе данных, когда две записи имеют одну и ту же дату. Я также хотел бы сортировать по идентификатору, где Id - поле с автоматическим приращением. Например.если есть две даты, которые являются одинаковыми, я хотел бы поддержать тот, у кого был более высокий идентификатор. Вы знаете, как я могу включить это в этот запрос? Я действительно должен был упомянуть Id в оригинальном вопросе, но не понимал, что будет трудно адаптировать его к моей базе данных. – user989266

+0

Я попробовал новый запрос, учитывающий идентификатор, но если все даты установлены одинаково, запрос не возвращается. Я попробовал SQL Fiddle: http://sqlfiddle.com/#!7/3bb0e/2. Это очень сложная проблема. : \ – user989266

Смежные вопросы