Как написать запрос, выбирающий разумные компромиссы? - PullRequest
2 голосов
/ 16 апреля 2011

В таблице у меня есть два столбца obs и abd. Я заинтересован в поиске низкие значения для obs и abd, но более низкое значение для abd более важно, чем низкое значение для обс. В реальном мире у меня есть компромисс между низким obs и низким abd, который нелегко определить математически и было бы трудно объяснить, но дело в том, что то, что я хочу видеть из запроса, это некоторые данные, которые сделали бы разумные компромиссы. Я хотел бы знать несколько пар данных в пределах диапазон значений obs. Например:

mysql> select obs, abd from flow where obs < 2000 order by abd,obs limit 10;

    +------+--------------+
    | obs  | abd          |
    +------+--------------+
    | 1372 | 0.0000004744 |
    | 1734 | 0.0000017704 |
    | 1010 | 0.0000017716 |
    | 1999 | 0.0000017716 |
    | 1637 | 0.0000036486 |
    |  383 | 0.0000066084 |
    |  745 | 0.0000066084 |
    | 1107 | 0.0000066084 |
    | 1469 | 0.0000066084 |
    | 1831 | 0.0000066084 |
    +------+--------------+

Из приведенных выше результатов видно, что существует несколько значений obs, которые имеют одинаковое значение abd. Меня интересует только один с самым низким значением obs для каждого значения abd. Все остальные дублированные значения abd должны быть отброшены. Это легко сделать использование предложения group by:

mysql> select obs, abd from flow where obs < 2000 group by abd order by abd,obs limit 10;

    +------+--------------+
    | obs  | abd          |
    +------+--------------+
    | 1372 | 0.0000004744 |
    | 1734 | 0.0000017704 |
    | 1010 | 0.0000017716 |
    | 1637 | 0.0000036486 |
    |  383 | 0.0000066084 |
    |  648 | 0.0000066096 |
    | 1540 | 0.0000097586 |
    | 1928 | 0.0000109544 |
    | 1566 | 0.0000119724 |
    |  913 | 0.0000119736 |
    +------+--------------+

Пока все хорошо. Теперь проблема в том, что, увидев первый запись где obs 1372 а abd 0.0000004744 меня не интересует видя вторую запись, где оба obs и abd выше. я интересно видеть третью запись, где obs ниже, а abd выше, потому что есть компромисс между obs и abd. Опять я не заинтересован в том, чтобы видеть четвертую запись, потому что она имеет значения obs и ABD, которые оба выше, чем то, что уже показано в третьем запись. Пятая запись мне особенно интересна, потому что хотя значение abd несколько выше, значение obs намного ниже. Что касается остальных записей, я бы не хотел их видеть, потому что у них есть и более высокие obs и abd чем то, что уже было замечено.

В целом, я хотел бы запрос, который бы показал мне:

+------+--------------+
| obs  | abd          |
+------+--------------+
| 1372 | 0.0000004744 |
| 1010 | 0.0000017716 |
|  383 | 0.0000066084 |
+------+--------------+

плюс еще семь записей, где obs продолжает уменьшаться и abd продолжает увеличиваться. Есть ли способ получить набор пар данных с одним запросом, не прибегая к процедуре?

Ответы [ 2 ]

1 голос
/ 16 апреля 2011

Можно просто сказать, что вы хотите фронт Парето

Это не будет быстрым, но попробуйте это:

SELECT a.obs
     , a.abd
FROM flow a
  LEFT JOIN flow b
    ON   ( b.obs <= a.obs AND b.abd <  a.abd )
      OR ( b.obs <  a.obs AND b.abd <= a.abd )
WHERE b.obs IS NULL
ORDER BY a.abd

Также:

SELECT a.obs
     , a.abd
FROM flow a
WHERE NOT EXISTS
  ( SELECT 1
    FROM flow b
    WHERE ( b.obs <= a.obs AND b.abd <  a.abd )
      OR ( b.obs <  a.obs AND b.abd <= a.abd )
  )
ORDER BY a.abd

И это:

SELECT a.obs
     , a.abd
FROM flow a
WHERE NOT EXISTS
  ( SELECT 1
    FROM flow b
    WHERE b.obs <= a.obs
      AND b.abd <  a.abd
  )
  AND NOT EXISTS
  ( SELECT 1
    FROM flow b
    WHERE b.obs < a.obs
      AND b.abd = a.abd
  )
ORDER BY a.abd

или это:

SELECT a.obs
     , a.abd
FROM flow a
WHERE NOT EXISTS
  ( SELECT 1
    FROM flow b
    WHERE b.obs <= a.obs
      AND b.abd <= a.abd
      AND (b.obs, b.abd) <> (a.obs, a.abd)
  )
ORDER BY a.abd

Проверьте, какая из 4 быстрее.Я бы предположил 4-й, если у вас есть индексы на obs и abd.Или лучше (как указал Unreason) два индекса: один на (obs, abd) и один на abd.


ОБНОВЛЕНИЕ: (небольшая поправка к 3-му запросу).

1 голос
/ 16 апреля 2011

Чтобы получить самое низкое obs на abd, вот как вы идете:

select min(obs), abd
from flow
where obs < 2000 
group by abd 
order by abd

Но мне кажется, что правило компромисса является своего рода специальным. Вы должны попытаться выяснить лучшие правила, которые вы можете придумать, и они положат их на стол, чтобы мы могли достичь того, что вы пытаетесь сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...