2014-01-07 2 views
3

Как получить все записи, где значение больше предыдущего. Например, первый диапазон в таблице ниже, начинаются ID 1 и заканчивается идентификатором 6, в следующий диапазон составляет от 7 до 10, и т.д. ...выберите диапазон, когда значение больше, чем в предыдущем значении

id Open 
1 1.30077 
2 1.30088 
3 1.30115 
4 1.30132 
5 1.30135 
6 1.30144 
7 1.30132 
8 1.30137 
9 1.30152 
10 1.30158 
11 1.30149 
12 ... 
+2

Являются ли идентификаторы гарантированно последовательными или же им приходится иметь дело с пробелами? – Barmar

ответ

2

ВАШ Выборочные данные

USE test 
DROP TABLE IF EXISTS rangedata; 
CREATE TABLE rangedata 
(
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    open FLOAT 
) ENGINE=MyISAM; 
INSERT INTO rangedata (open) VALUES 
(1.30077),(1.30088),(1.30115),(1.30132), 
(1.30135),(1.30144),(1.30132),(1.30137), 
(1.30152),(1.30158),(1.30149), 
(1.30077),(1.30088),(1.30115),(1.30132), 
(1.30135),(1.30144),(1.30132),(1.30137), 
(1.30152),(1.30158),(1.30149), 
(1.30077),(1.30088),(1.30115),(1.30132), 
(1.30135),(1.30144),(1.30132),(1.30137), 
(1.30152),(1.30158),(1.30149); 

ВАШ SAMPLE DATA LOADED

mysql>  USE test 
Database changed 
mysql>  DROP TABLE IF EXISTS rangedata; 
Query OK, 0 rows affected (0.01 sec) 

mysql>  CREATE TABLE rangedata 
    ->  (
    ->  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    ->  open FLOAT 
    -> ) ENGINE=MyISAM; 
Query OK, 0 rows affected (0.09 sec) 

mysql>  INSERT INTO rangedata (open) VALUES 
    ->  (1.30077),(1.30088),(1.30115),(1.30132), 
    ->  (1.30135),(1.30144),(1.30132),(1.30137), 
    ->  (1.30152),(1.30158),(1.30149), 
    ->  (1.30077),(1.30088),(1.30115),(1.30132), 
    ->  (1.30135),(1.30144),(1.30132),(1.30137), 
    ->  (1.30152),(1.30158),(1.30149), 
    ->  (1.30077),(1.30088),(1.30115),(1.30132), 
    ->  (1.30135),(1.30144),(1.30132),(1.30137), 
    ->  (1.30152),(1.30158),(1.30149); 
Query OK, 33 rows affected (0.00 sec) 
Records: 33 Duplicates: 0 Warnings: 0 

mysql> 

QUERY ИСПОЛЬЗОВАНИЕ JOINS

Вот это LEFT JOIN запрос

SET @grp = 1; 
SELECT A.open prev,(@grp:[email protected]+IF(A.open<B.open,1,0)) group_number 
FROM rangedata A LEFT JOIN rangedata B ON A.id= B.id+1; 

Вот его выход

mysql> SELECT A.open prev,(@grp:[email protected]+IF(A.open<B.open,1,0)) group_number 
    -> FROM rangedata A LEFT JOIN rangedata B ON A.id= B.id+1; 
+---------+--------------+ 
| prev | group_number | 
+---------+--------------+ 
| 1.30088 |   1 | 
| 1.30115 |   1 | 
| 1.30132 |   1 | 
| 1.30135 |   1 | 
| 1.30144 |   1 | 
| 1.30132 |   2 | 
| 1.30137 |   2 | 
| 1.30152 |   2 | 
| 1.30158 |   2 | 
| 1.30149 |   3 | 
| 1.30077 |   4 | 
| 1.30088 |   4 | 
| 1.30115 |   4 | 
| 1.30132 |   4 | 
| 1.30135 |   4 | 
| 1.30144 |   4 | 
| 1.30132 |   5 | 
| 1.30137 |   5 | 
| 1.30152 |   5 | 
| 1.30158 |   5 | 
| 1.30149 |   6 | 
| 1.30077 |   7 | 
| 1.30088 |   7 | 
| 1.30115 |   7 | 
| 1.30132 |   7 | 
| 1.30135 |   7 | 
| 1.30144 |   7 | 
| 1.30132 |   8 | 
| 1.30137 |   8 | 
| 1.30152 |   8 | 
| 1.30158 |   8 | 
| 1.30149 |   9 | 
| 1.30077 |   9 | 
+---------+--------------+ 
33 rows in set (0.01 sec) 

QUERY БЕЗ JOINS

Используя пользовательские переменные, вы просто контролировать каждую строку и видеть, когда предыдущее значение больше. Готовы к запросу? Вот оно:

SET @prev = '0.00000'; 
SET @grp = 1; 
SELECT id,open,(@grp:[email protected]+increasing) group_number FROM 
(SELECT id,open,IF(@prev<=open,0,1) increasing,(@prev:=open) FROM rangedata) A; 

Вот ваши данные выборки в три раза:

Вот выполнение указанного в запросе:

mysql> SET @prev = '0.00000'; 
Query OK, 0 rows affected (0.00 sec) 

mysql> SET @grp = 1; 
Query OK, 0 rows affected (0.00 sec) 

mysql> SELECT id,open,(@grp:[email protected]+increasing) group_number FROM 
    -> (SELECT id,open,IF(@prev<=open,0,1) increasing,(@prev:=open) FROM rangedata) A; 
+----+---------+--------------+ 
| id | open | group_number | 
+----+---------+--------------+ 
| 1 | 1.30077 |   1 | 
| 2 | 1.30088 |   1 | 
| 3 | 1.30115 |   1 | 
| 4 | 1.30132 |   1 | 
| 5 | 1.30135 |   1 | 
| 6 | 1.30144 |   1 | 
| 7 | 1.30132 |   2 | 
| 8 | 1.30137 |   2 | 
| 9 | 1.30152 |   2 | 
| 10 | 1.30158 |   2 | 
| 11 | 1.30149 |   3 | 
| 12 | 1.30077 |   4 | 
| 13 | 1.30088 |   4 | 
| 14 | 1.30115 |   4 | 
| 15 | 1.30132 |   4 | 
| 16 | 1.30135 |   4 | 
| 17 | 1.30144 |   4 | 
| 18 | 1.30132 |   5 | 
| 19 | 1.30137 |   5 | 
| 20 | 1.30152 |   5 | 
| 21 | 1.30158 |   5 | 
| 22 | 1.30149 |   6 | 
| 23 | 1.30077 |   7 | 
| 24 | 1.30088 |   7 | 
| 25 | 1.30115 |   7 | 
| 26 | 1.30132 |   7 | 
| 27 | 1.30135 |   7 | 
| 28 | 1.30144 |   7 | 
| 29 | 1.30132 |   8 | 
| 30 | 1.30137 |   8 | 
| 31 | 1.30152 |   8 | 
| 32 | 1.30158 |   8 | 
| 33 | 1.30149 |   9 | 
+----+---------+--------------+ 
33 rows in set (0.00 sec) 

Ключевой момент заключается в следующем: Каждый раз, когда появляется новый номер группы, что сообщает вам о снижении следующего значения.

ОБРАТИТЕ ВНИМАНИЕ РЕЗУЛьТАТа тождествен ДЛЯ ОБА Запрашивает

РИСКОВАННОЙ: Второй запрос не является идеальным решением в случае, если есть некоторые проблемы с плавающей точкой между prev и open. Если они смехотворно близки друг к другу, это может быть неправильно. Это лучше всего попробовать за пределами написания хранимой процедуры.

0

Диапазоны могут быть пронумерованы, используя этот запрос:

SELECT id, open, range_number 
FROM( 
    SELECT *, 
     if(@lastopen<open,@grp,@grp:[email protected]+1) range_number, 
     @lastopen:=open 
    FROM table1, 
    (select @lastopen:=null,@grp:=0) qqq 
    ORDER BY id 
) qqq; 

Демо: http://www.sqlfiddle.com/#!2/b1bb8/9

| ID |   OPEN | RANGE_NUMBER | 
|----|----------------|--------------| 
| 1 | 1.300770044327 |   1 | 
| 2 | 1.300879955292 |   1 | 
| 3 | 1.301149964333 |   1 | 
| 4 | 1.301319956779 |   1 | 
| 5 | 1.30134999752 |   1 | 
| 6 | 1.301440000534 |   1 | 
| 7 | 1.301319956779 |   2 | 
| 8 | 1.301370024681 |   2 | 
| 9 | 1.301519989967 |   2 | 
| 10 | 1.30157995224 |   2 | 
| 11 | 1.301489949226 |   3 | 
0
SELECT startid,MAX(id) FROM (
    SELECT 
     @currentid := IF(@previous <= open,@currentid,id) as startid, 
     @previous := open, 
     id 
    FROM ranges 
    JOIN (SELECT @currentid := MIN(id), @previous := MIN(open) FROM ranges) as variables 
    ORDER BY id) runningscan 
GROUP BY startid ORDER BY startid + 0; 

Смотреть это на SQLFiddle: http://sqlfiddle.com/#!2/e3cea/3

Что это делает: в runningscan подзапрос, он проходит через таблицу один раз, сохраняя метчики, если open больше или меньше, чем предыдущий open (хранится в переменной @previous. Это дает вам список со всеми идентификаторами, а идентификатор запускает прерывание выше (или равно) «run». Из этого нам нужно только найти наивысший id для начального id, поэтому мы помещаем его в подзапрос для простой конструкции max. Пробелы в столбце id не представляют проблемы. Если одна строка не может быть диапазоном (i.e: open опускается дважды или более подряд), добавьте в внешний запрос WHERE startid < id.Если вам нужны диапазоны минимального количества строк для квалификации, это диапазон более 1, добавьте HAVING COUNT(*) > your_desired_minimum.