Помогите в создании запроса

skytskyi

Новичок
Помогите в создании запроса

Есть таблица Tabl с полями id-номер записи, Start- начало промежутка, End - конец промежутка на числовой оси. Нужно создать запрос, который должен выводить объединение значений отрезков на числовой осе. Например, если у меня задана таблица со значениями:

id |Start |End
01| 5 | 7
02| 10 | 100
03| 90 | 180
04| 200 | 300
05| 220 | 240
06| 260 | 280

То в результате выполнения запроса у меня должна получится следующая таблица

|Start |End
| 5 | 7
| 10 | 180
| 200 | 300
Буду очень признателен за помощь. Спасибо.
 

alpes

Весь мир на ладони
не понятно по какому признаку должно происходить объединение
 

skytskyi

Новичок
Объединение должно происходить по следующему признаку, если промежуток входит в какой та другой больший, от первого, то ми оставляем, этот который есть больший, то есть если у нас есть два промежутка например начало 200, конец 300, і другой с началом в 220 і концом в 240, то ми оставляем первый, поскольку второй входит в него. Если у нас два промежутки с началом в 10 і 100 і второй с началом в 90 і концом в 180, то ми их объединяем. Ну а если у нас два промежутки с началом в 5 и концом в 7 і промежуток с началом в 10 и концом в 100, то ми их так и оставляем.
 

Wicked

Новичок
alpes
объединение должно происходить по признаку пересечения интервалов [Start, End].

skytskyi
имхо одним запросом не получится.
 

skytskyi

Новичок
это я знаю, а как именно нужно оформить запрос, а то я даже не знаю с чего начать
 

zerkms

TDD infected
Команда форума
Код:
mysql> SELECT * FROM `t`;
+----+-------+------+
| id | start | end  |
+----+-------+------+
|  1 |     5 |    7 |
|  2 |    10 |  100 |
|  3 |    90 |  180 |
|  4 |   200 |  300 |
|  5 |   220 |  240 |
|  6 |   260 |  280 |
+----+-------+------+
6 rows in set (0.00 sec)


mysql> DROP TABLE IF EXISTS `temporary`;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE  TABLE `temporary` SELECT DISTINCT `t1`.`start`, IF(`t2`.`end` > `
t1`.`end`, `t2`.`end`, `t1`.`end`) AS `end` FROM `t` `t1` LEFT JOIN `t` `t2` ON
`t2`.`start` > `t1`.`start` AND `t2`.`start` < `t1`.`end` ORDER BY `t1`.`start`;

Query OK, 6 rows affected (0.03 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> SELECT `t3`.`start`, `t3`.`end`, COUNT(*) AS `cnt` FROM `temporary` `t3`
LEFT JOIN `temporary` `t4` ON `t3`.`start` >= `t4`.`start` AND `t3`.`end` <= `t4
`.`end` GROUP BY `t3`.`start`, `t3`.end HAVING `cnt` = 1;
+-------+------+-----+
| start | end  | cnt |
+-------+------+-----+
|     5 |    7 |   1 |
|    10 |  180 |   1 |
|   200 |  300 |   1 |
+-------+------+-----+
3 rows in set (0.01 sec)
ps: можно сделать таблицу TEMPORARY конечно же
 

chira

Новичок
без темпорари
Код:
SELECT DISTINCT MIN(LEAST(b1.start,IFNULL(b2.start,b1.start))) start, MAX(GREATEST(b1.end,IFNULL(b2.end,b1.end))) end
FROM b b1
	LEFT JOIN b b2 ON b1.start <= b2.end and b1.end >= b2.start and b1.id > b2.id
GROUP BY IFNULL(b2.start,b1.start),IFNULL(b2.end,b1.end);
 

zerkms

TDD infected
Команда форума
chira
респект

ps:
Код:
MIN(LEAST(b1.start,b2.start)) start, MAX(GREATEST(b1.end,b2.end))
 

chira

Новичок
в таком варианте некоторые значения могут выпасть ...
Код:
mysql> select greatest(1000,null);
+------------------+
| greatest(1000,null) |
+------------------+
|             NULL |
+------------------+
1 row in set (0.01 sec)
 

zerkms

TDD infected
Команда форума
pps: да и
and b1.id > b2.id
вроде тоже можно убрать..

-~{}~ 07.05.06 02:14:

Код:
mysql> select greatest(1,null);
+------------------+
| greatest(1,null) |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)

mysql> select version();
+------------+
| version()  |
+------------+
| 4.1.14-log |
+------------+
1 row in set (0.00 sec)
 

itprog

Cruftsman
Код:
mysql> select greatest(1,null);
+------------------+
| greatest(1,null) |
+------------------+
|             NULL |
+------------------+
1 row in set (0.24 sec)

mysql> select version();
+---------------------+
| version()           |
+---------------------+
| 5.0.21-community-nt |
+---------------------+
1 row in set (0.01 sec)
 

chira

Новичок
если таблица не большая, то сойдёт и такой вариант
Код:
SELECT DISTINCT MIN(LEAST(b1.start,b2.start)) start, MAX(GREATEST(b1.end,b2.end)) end
FROM b b1
	INNER JOIN b b2 ON b1.start <= b2.end and b1.end >= b2.start
GROUP BY b2.start,b2.end;
 

chira

Новичок
с NULL в разных версиях MySQL работает по разному.
в пятой более правильно (по ссылке от zerkms)
если одно из значений в списке NULL, то общий результат неопределён, т.е. тоже NULL
 

zerkms

TDD infected
Команда форума
хм.... тем не менее мне например логичнее что 1 > NULL

-~{}~ 07.05.06 02:32:

с другой стороны - тогда получается неопределённость -1 ? NULL ;)))
 

zerkms

TDD infected
Команда форума
chira
я понимаю..... именно поэтому я и указал на -1 ? NULL, тем самым соглашаясь, что всё в версии 5.0.13+ сделано "правильнее" с точки зрения логики
 
Сверху