powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Возможно ли сделать прореженную выборку простым запросом?
12 сообщений из 12, страница 1 из 1
Возможно ли сделать прореженную выборку простым запросом?
    #34365704
Tertium Organum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
вопщем задачка такая. Есть таблица в которой несколько интовых полей и поле таймстамп. это вроде как показания датчиков в конкретные моменты времени. нужно выбрать получить на выходе ровсет, в котором строки по дате друх от друга различаются на не больше чем минуту, причем значения счетчиков не равны?
вроде бы простая задачка, ан на MSSQL мне пришлось хп писать, ну и на постгре тоже пока хп.
а может можно както так SELECT составить? что скажете?
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34365769
Бабичев Сергей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Приведи тестовый набор данных и желаемый вид результата.
Постарайся учесть все нюансы распределения данных (наличие двух соседних записей, с разностью по времени более минуты, наличие записей с разностью по времени менее минуты, но с одинаковыми показаниями счетчиков)
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34366102
Tertium Organum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ммм... вобщем, вот что у меня есть.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
CREATE TABLE "public"."stats" (
  "id" SERIAL, 
  "place_no" SMALLINT DEFAULT  0  NOT NULL, 
  "club_id" INTEGER DEFAULT  0  NOT NULL, 
  "currentin" BIGINT DEFAULT  0  NOT NULL, 
  "currentout" BIGINT DEFAULT  0  NOT NULL, 
  "last_query" TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, 
  CONSTRAINT "stats_pkey" PRIMARY KEY("id"), 
  CONSTRAINT "stats_place_no_key" UNIQUE("place_no", "club_id", "last_query")
) WITHOUT OIDS;

CREATE RULE "stats_dup_ignore" AS ON INSERT TO "public"."stats" 
WHERE (EXISTS ( SELECT stats.place_no FROM stats WHERE stats.place_no = new.place_no AND stats.club_id = new.club_id AND stats.last_query = new.last_query))
DO INSTEAD NOTHING;

--для выброса 
CREATE TABLE "public"."get_ai_result" 
(
  "currentin" BIGINT, 
  "currentout" BIGINT, 
  "last_query" TIMESTAMP WITHOUT TIME ZONE
) WITHOUT OIDS;

--ХП


DROP FUNCTION get_ai(place integer, club integer, begin_val_ timestamp without time zone, end_val_ timestamp without time zone, minute_period integer);

CREATE OR REPLACE FUNCTION get_ai(place integer, club integer, begin_val_ timestamp without time zone, end_val_ timestamp without time zone, minute_period integer)
  RETURNS SETOF get_ai_result AS
$BODY$
DECLARE
	str text;
	tmp timestamp;
	begin_val timestamp;    
	end_val timestamp;    
	prev_last_datime timestamp;    
	prev_last_IN bigint;    
	prev_last_OUT bigint;  
	rec get_ai_result%ROWTYPE;
        ret_rec record;
	real_num bigint;
	dt2 timestamp;
BEGIN
	end_val = end_val_;    
	begin_val = begin_val_;    
	if (end_val < begin_val) then   
		tmp = end_val;
		end_val = begin_val;    
		begin_val = tmp;    
	end if;

	--первая запись
	select last_query into prev_last_datime from club_stats where club_id = club order by last_query asc limit  1 ;
	if (begin_val < prev_last_datime) then  
		begin_val = prev_last_datime; 
	end if;

	--последняя запись
	select last_query into prev_last_datime from club_stats where club_id = club order by last_query desc limit  1 ;
	if (end_val > prev_last_datime)  then
		end_val = prev_last_datime;  
	end if;

	prev_last_datime = (begin_val - ((minute_period::text||' minutes ' )::interval))::timestamp;
	prev_last_IN  = - 1 ;
	prev_last_OUT = - 1 ;

	real_num =  0 ; 	
	IF (minute_period =  0 ) THEN
		for ret_rec in select currentIN, currentOUT, last_query from stats where 
			place_no = place and club_id = club and last_query >= begin_val and last_query <= end_val order by last_query
		LOOP
			return next ret_rec;
			real_num = real_num +  1 ;
		END LOOP;
	ELSE
		FOR rec IN SELECT currentIN, currentOUT, last_query FROM stats where place_no = place and club_id = club and last_query >= begin_val and last_query <= end_val order by last_query
		LOOP 
			if ((EXTRACT(EPOCH FROM (rec.last_query - prev_last_datime)) >= minute_period* 60 ) and
			   (rec.currentIN <> prev_last_IN or rec.currentOUT <> prev_last_OUT)) then
				select rec.currentIN, rec.currentOUT, rec.last_query into ret_rec; return next ret_rec;
				prev_last_datime = rec.last_query;    
				prev_last_IN  = rec.currentIN;  
				prev_last_OUT = rec.currentOUT;  
				real_num = real_num+ 1 ;   
			end if;
		END LOOP;
	END IF;


	--компенсация до минимального количества записей (2 или 1) 
	if (real_num =  1 )  then  
		select last_query into dt2 from stats where  place_no = place and club_id = club and last_query >= begin_val and last_query <= end_val 
			order by last_query desc limit  1 ;
		if  (prev_last_datime is not null and  prev_last_datime <> dt2) then
			select prev_last_IN,prev_last_OUT,prev_last_datime into ret_rec; return next ret_rec;
			real_num = real_num +  1 ;
		end if;
	end if;
	if (real_num =  0 ) then   
		select  0 ::bigint,  0 ::bigint, begin_val into ret_rec; return next ret_rec;
		real_num = real_num +  1 ;
		if (end_val <> begin_val) then
			select  0 ::bigint,  0 ::bigint, end_val into ret_rec; return next ret_rec;
			real_num = real_num +  1 ;
		end if;
	end if;
 
	--добавление первой строкой (если смотреть в порядке даты) количества строк в результате   
	select real_num,real_num, timestamp '19000101' into ret_rec; return next ret_rec;

	RETURN;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;


--вызов ф-ции собссно - получить данные для аппарата 1 из зала 2 с 2000 по 2010 год с разбросом не менее 10 минут
select * from get_ai( 1 , 2 , '20000101', '20100101',  10 ) order by last_query ; 


исходный кортеж (select * from stats where club_id = 2 and place_no = 1 order by last_query):
"id";"place_no";"club_id";"currentin";"currentout";"last_query""226069";"1";"2";"3252";"2305";"2006-01-01 00:00:00""226109";"1";"2";"6949";"6067";"2006-01-01 00:00:30""226149";"1";"2";"8851";"8841";"2006-01-01 00:01:00""226189";"1";"2";"9693";"11444";"2006-01-01 00:01:30""226229";"1";"2";"14420";"12481";"2006-01-01 00:02:00""226269";"1";"2";"15853";"14170";"2006-01-01 00:02:30""226309";"1";"2";"17924";"15631";"2006-01-01 00:03:00"..."1262629";"1";"2";"64851367";"64416277";"2006-01-09 23:57:00""1262669";"1";"2";"64855681";"64419252";"2006-01-09 23:57:30""1262709";"1";"2";"64857460";"64419537";"2006-01-09 23:58:00""1262749";"1";"2";"64862068";"64421969";"2006-01-09 23:58:30""1262789";"1";"2";"64865770";"64426617";"2006-01-09 23:59:00""1262829";"1";"2";"64865800";"64428536";"2006-01-09 23:59:30"

и результат чтото вроде:

"currentin";"currentout";"last_query""1296";"1296";"1900-01-01 00:00:00" --1296 записей в ровсете"3252";"2305";"2006-01-01 00:00:00""44342";"48034";"2006-01-01 00:10:00""97735";"100387";"2006-01-01 00:20:00""150207";"156841";"2006-01-01 00:30:00"..."64646305";"64224794";"2006-01-09 23:20:00""64702865";"64275545";"2006-01-09 23:30:00""64759635";"64326561";"2006-01-09 23:40:00""64807066";"64379842";"2006-01-09 23:50:00"

---
вот так это работает на ХП. можно ли это сделать просто select'ом?
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34366205
Serik Akhmetov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
текст не читал, но интуиция мне подсказывает, что заменить процедуру на три экрана на селект будет совсем не просто :)
а чем не устраивает вариант с процедурой ?
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34366227
Бабичев Сергей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Tertium Organum
вот так это работает на ХП. можно ли это сделать просто select'ом?Давай немного всё упростим.
Подготовь тестовый набор данных из 20-30 строк максимум. Пусть это будут даже данные из таблицы, расскажи на словах алгоритм их обработки процедурой, приведи результат этой обработки.
А там видно будет.
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34366281
Бабичев Сергей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообще, по словесному описанию из первого поста, напрашивается банальнейший запрос с EXISTS-подзапросом.
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34366351
Бабичев Сергей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Бабичев СергейВообще, по словесному описанию из первого поста, напрашивается банальнейший запрос с EXISTS-подзапросом.Ну что-то вроде вот такого:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
select t1.* 
  from stats t1
 where exists(
               select null 
			     from stats t2
			    where t1.id != t2.id
			      and t2.last_query between t1.last_query -  1 / 24 / 60 
			                            and t1.last_query +  1 / 24 / 60 
			      and (
			            t1.currentin != t2.currentin
			            or
			            t1.currentout != t2.currentout
				      )
			 ) 


Возможно, что вместо выделенного желтым для твоей задачи нужно будет написать вот такое условие (если проверка должна делаться только вверх по списку):
Код: plaintext
1.
2.
			      and t2.last_query between t1.last_query -  1 / 24 / 60 
			                            and t1.last_query
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34366428
Tertium Organum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
запустил вот такое
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
select t1.* 
  from stats t1
 where club_id =  1  and place_no =  1  and exists(
               select null 
			     from stats t2
			    where t1.id != t2.id and club_id =  1  and place_no =  1 
			      and t2.last_query - t1.last_query > interval '1 minute'
			      and (t1.currentin != t2.currentin  or t1.currentout != t2.currentout )
			 ) 

жду до сих пор но что-то мне подсказывает, что не дождусь - там миллион записей, из которых для club_id = 1 and place_no = 1 - 25000. из них должно выбрать чтото типа 1200
прошло порядка 300 секунд. хп это делает за 3,5 сек. мда, вложенные селекты это круть :)
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34367674
Jelis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А если просто группировать по времени, вернее по функции округляющей время до нужного интревала?
Код: plaintext
1.
2.
3.
SELECT avg(currentin), avg(currentout), time_to_ten_minuts(last_query) 
FROM Stats 
GROUP BY time_to_ten_minuts(last_query);
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34370105
Бабичев Сергей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Tertium Organumзапустил вот такое
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
select t1.* 
  from stats t1
 where club_id =  1  and place_no =  1  and exists(
               select null 
			     from stats t2
			    where t1.id != t2.id and club_id =  1  and place_no =  1 
			      and t2.last_query - t1.last_query > interval '1 minute'
			      and (t1.currentin != t2.currentin  or t1.currentout != t2.currentout )
			 ) 

жду до сих пор но что-то мне подсказывает, что не дождусь - там миллион записей, из которых для club_id = 1 and place_no = 1 - 25000. из них должно выбрать чтото типа 1200
прошло порядка 300 секунд. хп это делает за 3,5 сек. мда, вложенные селекты это круть :)Для [not] exists-подзапросов крайне желательно наличие подходящего индекса. Возможно в твоем случае потребуется составной индекс по полям (club_id asc, place_no asc, last_query asc).
Ну и выделенное желтым условие нужно переделать на тот манер, что я тебе говорил, то есть нужно исключить упоминание поля t2.last_query в вычисляемых выражениях, а лучше сравнивать это поле с какими-то вычисляемыми выражениями на основе поля t1.last_query. Иначе наличие индекса по трем полям в плане селективности будет эквивалентно индексу по двум полям (club_id asc, place_no asc), но при этом будет гораздо менее эффективно в плане ввода-вывода.

Кроме того, можно избавиться от exists-подзапроса, переписав запрос через join.
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34370729
Бабичев Сергей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Бабичев СергейКроме того, можно избавиться от exists-подзапроса, переписав запрос через join.Точнее, через LEFT JOIN.
...
Рейтинг: 0 / 0
Возможно ли сделать прореженную выборку простым запросом?
    #34371079
Tertium Organum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
...ну вобщем-то все равно выясняется, что функция, которая просматривает селект-звездочку и отдает с некоторой гранулярностью по времени записи, работает ... ну, во много раз быстрее подзапроса. Вопщем на то они есть видимо, что нельзя запросом можно ХП
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Возможно ли сделать прореженную выборку простым запросом?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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