powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Другие СУБД [игнор отключен] [закрыт для гостей] / Формирование отчета об изменении данных без повторов (извещения о событиях)
5 сообщений из 5, страница 1 из 1
Формирование отчета об изменении данных без повторов (извещения о событиях)
    #35616874
sleepyhead
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте!

Я опишу сначала упрощенный вариант задачи, а ниже объясню откуда она появилась и какое решение мне удалось получить. Предположим, есть такая таблица с данными:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
create table T (X integer unique, Y integer);
insert into T values ( 1 ,  1 );
insert into T values ( 2 ,  1 );
insert into T values ( 3 ,  1 );
insert into T values ( 4 ,  2 );
insert into T values ( 5 ,  3 );
insert into T values ( 6 ,  3 );
insert into T values ( 7 ,  3 );
insert into T values ( 8 ,  4 );
insert into T values ( 9 ,  5 );

Подскажите, пожалуйста, как можно написать запрос, чтобы получить такой результат:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
X	Y
---------
 1 	 1 
 4 	 2 
 5 	 3 
 8 	 4 
 9 	 5 

В результате должен получится отсортированный по X вывод, в котором есть только такие строки, в которых содержится отличное от ПРЕДЫДУЩЕЙ значение Y. Хотя набор исходных данных не упорядочен по определению, проще понять, что требуется, смотрять на вывод "select * from T" и сравнивая значения "предыдущей" и "текущей" строк:

X Y
---------
1 1 <-- эта строка должна быть в результате - у нее просто нет "предыдущей"
2 1 <-- не должна, не изменился Y
3 1 <-- не должна, не изменился Y
4 2 <-- должна, изменился Y
5 3 <-- должна, изменился Y
6 3 <-- не должна, не изменился Y
7 3 <-- не должна, не изменился Y
8 4 <-- должна, изменился Y
9 5 <-- должна, изменился Y


К моему сожалению, пока мои знания SQL ограничены 2-хдневным чтением Стандарта SQL-92, а потому получающиеся конструкции выглядят крайне неуклюже, хотя как-то иногда и работают. Я пока не "чувствую", какой из подходов сработает в той или иной ситуации, поэтому хотелось бы увидеть решение, которое использовали бы профессионалы.

На мой взгляд, просто удалить дубликаты нельзя, поскольку Y может иметь произвольное значение, а удалять дубли надо только для соседних строк. Например, если "select * from T" выдает:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
X	Y
---------
 1 	 1  	
 2 	 1 
 3 	 1 
 4 	 2 
 5 	 2 
 6 	 1 
 7 	 1 
 8 	 2 
 9 	 1 

то в результате выполнения требуемого запроса должно получится:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
X	Y
---------
 1 	 1  	
 4 	 2 
 6 	 1 
 8 	 2 
 9 	 1 


Попытки так и эдак применить удаление дублей не увенчались успехом. Возможно, я просто не умею их готовить... У меня же в итоге получился вот такой ужос:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
select * from T t1
where (x = (select min(x) from T)) -- первая строка всегда включена в результат
  or exists (select * from T t2 
             where (y <> t1.y) -- проверит, отличаются ли "соседние" строки
               and (x = (select max(x) from T t3 -- вернет наибольший х из всех меньших, чем текущий
                         where (t1.x > t3.x)))) 
order by x;

Решение использует тот факт, что все значения x - различны. Только тогда имеет смысл сравние для выбора наибольшего из всех меньших. Проверял я работу операторов в SQLite, как наболее простой и понятном мне инструменте с SQL, который смог найти с ходу. Возможно, из-за этого у меня возникла проблема: почему-то select max(x) всегда возвращает результат, даже если таблица пустая! Правда, в этом случае результат NULL, но его не отличить с помощью оператора exists. Пришлось сделать трюк с проверкой в еще одном select x = select max(x), где сравнение с NULL просто отбрасывается.



Задача возникла из необходимости сократить количество событий, которые требуют внимания оператора. Разнообразные данные ("состояния") генерируются несколькими источниками, но внимание требуется только тогда, когда "что-то случилось" - изменилось "состояние". Использование триггеров и пр. невозможно, есть уже готовый набор данных (протокол работы). Есть только отчет, где указаны "состояния" в хронологическом порядке, примерно вот так.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
date/time       state
---------------------
 22 : 21 : 34 	good 
 22 : 22 : 34 	good 
 22 : 23 : 34 	good (несколько тысяч good)
 22 : 24 : 34 	bad  (пара bad)
 22 : 25 : 34 	bad 
 22 : 26 : 34 	good  
 22 : 27 : 34 	good 
 22 : 28 : 34 	good 
 22 : 29 : 34 	bad
. . .

А хотелось бы иметь:

Код: plaintext
1.
2.
3.
4.
5.
6.
date/time       state
---------------------
 22 : 21 : 34 	good 
 22 : 24 : 34 	bad 
 22 : 26 : 34 	good 
 22 : 29 : 34 	bad

Объем отслеживаемых событий сокращается драматически.


Как же это можно сделать элегантным способом?
...
Рейтинг: 0 / 0
Формирование отчета об изменении данных без повторов (извещения о событиях)
    #35618617
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sleepyhead Хотя набор исходных данных не упорядочен по определению, проще понять, что требуется, смотрять на вывод "select * from T" и сравнивая значения "предыдущей" и "текущей" строк:В SQL несуществует понятий "предыдущая" и "следующая" строка. Если они есть в задаче - пытайся придумать как переформулировать задачу без них.

sleepyheadВозможно, из-за этого у меня возникла проблема: почему-то select max(x) всегда возвращает результат, даже если таблица пустая!Это не проблема, так и должно быть. Запрос с агрегатной функцией всегда выдает одну строку на группу. Если агрегат не может посчитаться (нет значений например) он возвращает null.


sleepyheadЗадача возникла из необходимости сократить количество событий, которые требуют внимания оператора. Разнообразные данные ("состояния") генерируются несколькими источниками, но внимание требуется только тогда, когда "что-то случилось" - изменилось "состояние". Использование триггеров и пр. невозможно, есть уже готовый набор данных (протокол работы). Есть только отчет, где указаны "состояния" в хронологическом порядке, примерно вот так.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
date/time       state
---------------------
 22 : 21 : 34 	good 
 22 : 22 : 34 	good 
 22 : 23 : 34 	good (несколько тысяч good)
 22 : 24 : 34 	bad  (пара bad)
 22 : 25 : 34 	bad 
 22 : 26 : 34 	good  
 22 : 27 : 34 	good 
 22 : 28 : 34 	good 
 22 : 29 : 34 	bad
. . .

А хотелось бы иметь:

Код: plaintext
1.
2.
3.
4.
5.
6.
date/time       state
---------------------
 22 : 21 : 34 	good 
 22 : 24 : 34 	bad 
 22 : 26 : 34 	good 
 22 : 29 : 34 	bad

Объем отслеживаемых событий сокращается драматически.


Как же это можно сделать элегантным способом?Такие задачи обычно решаются либо через хранимые процедуры, курсоры и временные таблицы. Либо через OLAP функции, но sqlite их делать не умеет пока.
...
Рейтинг: 0 / 0
Формирование отчета об изменении данных без повторов (извещения о событиях)
    #35618944
sleepyhead
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owlsleepyhead Хотя набор исходных данных не упорядочен по определению, проще понять, что требуется, смотрять на вывод "select * from T" и сравнивая значения "предыдущей" и "текущей" строк:В SQL несуществует понятий "предыдущая" и "следующая" строка.

Перед отправкой своего вопроса просмотрел форум и, зная, что часто вопрошающих тычут носом в факт "таблицы - это наборы данных, никак не упорядоченные", написал так, чтобы было понятно, что я тоже это уже понимаю . Особо подчеркнул, что "набор исходных данных не упорядочен по определению". И даже написал, что рассматриваю не исходный набор, а вывод - только, чтобы проще объяснить условие задачи. Согласитесь, что вывод может быть упорядоченным? Наверное, мне стоило написать "select * from T order by X ".

White OwlЕсли они есть в задаче - пытайся придумать как переформулировать задачу без них.
У меня есть отношение порядка, заданное для данных одного из столбцов (здесь - для Х). Т.е. действительно есть "предыдущий" и "следующий". И только используя эти понятия, я могу сформулировать задачу. Как их не называй, суть от этого не изменится. Вероятно, я просто не понимаю, что значит переформулировать задачу? Не могли бы Вы показать на каком-либо примере, хотя бы на этом, как это можно сделать?

White OwlЕсли агрегат не может посчитаться (нет значений например) он возвращает null. Спасибо, это я пропустил при изучении SQL!


White OwlТакие задачи обычно решаются либо через хранимые процедуры, курсоры и временные таблицы. Либо через OLAP функции, но sqlite их делать не умеет пока.
Спасибо, буду знать. Но в указанной задаче я не зря написал, что подобных возможностей нет, требуется извлечь отчет по указанной форме из уже готовой таблицы. Конкретно для этого случая есть какие-либо идеи? Какие есть проблемы с предложенным решением? Можно ли что-то улучшить в нем или же надо применить какой-то совершенно другой подход?
...
Рейтинг: 0 / 0
Формирование отчета об изменении данных без повторов (извещения о событиях)
    #35619004
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sleepyheadWhite OwlЕсли они есть в задаче - пытайся придумать как переформулировать задачу без них.У меня есть отношение порядка, заданное для данных одного из столбцов (здесь - для Х). Т.е. действительно есть "предыдущий" и "следующий". И только используя эти понятия, я могу сформулировать задачу. Как их не называй, суть от этого не изменится. Вероятно, я просто не понимаю, что значит переформулировать задачу? Не могли бы Вы показать на каком-либо примере, хотя бы на этом, как это можно сделать?Эту фразу я писал прочитав только первый пример, с пятью различными Y.
Второй пример и пример реальных данных уже действительно сложно описать по другому...

sleepyheadКонкретно для этого случая есть какие-либо идеи? Какие есть проблемы с предложенным решением? Можно ли что-то улучшить в нем или же надо применить какой-то совершенно другой подход?Проблем с предложенным решением я с ходу не вижу. Вроде-бы работает... Хотя я бы его переписал вот так:
Код: plaintext
1.
2.
select * from T t1
where t1.x=(select min(x) from T) or
      t1.y<>(select t2.y from T t2 where t2.x=(select max(t3.x) from T t3 where t3.x<t1.x))
Чуточку покороче, но не принципиально. И в сложносочиненных стейтментах я предпочитаю всегда явно указывать какому из алиасов принадлежит поле - потом проще разбираться будет.
...
Рейтинг: 0 / 0
Формирование отчета об изменении данных без повторов (извещения о событиях)
    #35619395
sleepyhead
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl, спасибо! Сейчас буду соображать, как работает Ваш запрос...

Действительно, это пока я сам запрос написал, понимаю, какое поле к чему относится, а вот разобраться, скажем, через неделю, будет сложновато... Совет мне кажется весьма дельным, впредь буду делать именно так!
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Другие СУБД [игнор отключен] [закрыт для гостей] / Формирование отчета об изменении данных без повторов (извещения о событиях)
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]