Удалить условие WHERE, если подзапрос не возвращает ни одной строки - PullRequest
0 голосов
/ 12 августа 2011

Я пишу сложный запрос MySQL и не могу понять, как его завершить.

Вот часть, которая доставляет мне неприятности (это только часть моего запроса):

SELECT * FROM table AS t1
WHERE date < (
    SELECT date FROM table AS t2 
    WHERE phase="B" AND t2.target = t1.target
)

По сути, у меня есть предметы, у каждого из которых есть дата, фаза (A, B, C) и цель. Для цели есть несколько предметов типа A, затем один и необязательный предмет типа B, затем предметы с типом C.

Для каждой цели я хочу выбрать все строки, соответствующие следующим условиям:

  1. Если есть элемент с фазой «B» (давайте назовем его itemX ), я хочу вернуть все элементы с датой ниже даты itemX
  2. Если нет элемента с фазой "B", я хочу вернуть все строки

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

Проблема здесь в том, что мой подзапрос не возвращает ни одной строки в случае 1, а одну ячейку в случае 2.

Если мы находимся в случае 1, все условие WHERE date < (...) не имеет значения и не должно применяться в запросе.

Я перепробовал несколько вариантов с IFNULL и EXISTS, но я думаю, что сделал это неправильно, потому что у меня продолжают появляться ошибки синтаксиса.

Ответы [ 5 ]

1 голос
/ 12 августа 2011
SELECT  m.*
FROM    (
        SELECT  target, MAX(date) AS maxdate
        FROM    mytable
        ) md
JOIN    mytable m
ON      m.target = md.target
        AND m.date <
        COALESCE
        (
        (
        SELECT  date
        FROM    mytable mb
        WHERE   mb.target = md.target
                AND mb.phase = 'B'
        ORDER BY
                mb.target, pmb.phase, mb.date
        LIMIT 1
        ),
        maxdate + INTERVAL 1 SECOND
        )

Создать два индекса:

mytable (target, date)
mytable (target, phase, date)

чтобы это работало быстро.

1 голос
/ 12 августа 2011

Возможно

SELECT *
FROM table AS t1
LEFT JOIN table AS t2 ON t2.target = t1.target AND (t1.date < t2.date)
WHERE (phase = 'B')

Я предполагаю, что table в вашем запросе на самом деле две таблицы, и вы не делаете самостоятельное соединение? Если это так, то вам придется указать, на какую таблицу phase вы ссылаетесь.

1 голос
/ 12 августа 2011

Вы можете попробовать

SELECT * FROM table AS t1
left join 
table as t2 
on t1.Target = t2.Target
and t2.phase="B"
where t2.target is null OR 
OR t1.date < t2.Date
0 голосов
/ 12 августа 2011
SELECT t1.*
  FROM table t1
  LEFT
  JOIN ( SELECT t.target
              , MIN(t.date) AS b_date
           FROM table t
          WHERE t.phase = 'B'
          GROUP BY t.target
       ) t2
    ON t1.target = t2.target AND t1.date < t2.b_date

Если есть какая-то гарантия, что у данной цели будет не более одной строки с максимумом "phase" = 'B', вы можете обойтись без MIN и GROUP BY, например:

SELECT t1.*
  FROM table t1
  LEFT
  JOIN ( SELECT t.target
              , t.date AS b_date
           FROM table t
          WHERE t.phase = 'B'
       ) t2
    ON t1.target = t2.target AND t1.date < t2.b_date
0 голосов
/ 12 августа 2011

Код, который вы разместили, называется «Один подзапрос на каждый анти-шаблон условия».Используйте ДЕЛО-КОГДА-ТО.

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