2014-02-11 3 views
0

боролись с этим в течение всего дня и хотели бы попросить о помощи, как сделать этот запрос. Моя проблема заключается в том, что в частях WHERE для подпрограммы INNER JOIN мне нужно использовать соответствующие значения из каждой обрабатываемой строки таблицы GC, и очевидно, что подзапрос ничего не знает о главном запросе, поэтому он терпит неудачу. Надеюсь, вы поймаете идею, что я пытаюсь acomplish здесь:Подзапросы WHERE нужны поля из основного запроса

SET @now=100; #sunix datetime 
SELECT a.id, b.maxdate 
    FROM GC AS a 
    INNER JOIN (
      SELECT 0 id_group, MAX(dt_active_to) AS maxdate 
       FROM GCDeals 
       WHERE dt_active_from > a.dt_lastused AND dt_active_from <= @now 
       GROUP BY id_group 

       UNION ALL 
       SELECT 1 id_group, MAX(dt_active_to) AS maxdate 
       FROM GCDeals 
       WHERE id_group <> 2 AND dt_active_from > a.dt_lastused AND dt_active_from <= @now 

       UNION ALL 
       SELECT 2 id_group, MAX(dt_active_to) AS maxdate 
       FROM GCDeals 
       WHERE id_group <> 1 AND dt_active_from > a.dt_lastused AND dt_active_from <= @now 
       GROUP BY id_group 
    ) AS b 
    ON a.id_group = b.id_group 

    LEFT JOIN GCMsg AS c 
    ON a.id = c.id_gc 

    WHERE a.is_active = 1 AND a.dt_lastused < @now AND c.id_gc IS NULL 
    ORDER BY a.id 

Спасибо вам

+0

Ваше заявление о выборе меня сбивает с толку. Вы группируете id_group. Таким образом, ваша таблица GCDeals имеет столбец id_group. Вы группируете его, а затем независимо от того, будет ли его значение заменено нулем во всех результирующих записях. И затем вы присоединяетесь к каждой записи GC с идентификатором 0 со всеми записями в GCDeals? Или id_group не colum в GCDeals (я думаю, MySQL это позволяет)? Тогда почему вы группируетесь буквально? Во всяком случае, это не выглядит хорошо для меня. –

+0

У GCDeals есть много сделок, которые присваиваются каждой из этих групп 0-унисекс, 1-мужчина, 2-женщина. В таблице GC есть все клиенты, где каждый из клиентов принадлежит к определенной группе. Трудная часть здесь состоит в том, что если клиент находится в группе 0, maxdate находится для 0,1,2 групп (поскольку унисекс охватывает все три группы - сам, мужчина и женщина), если в 1 - тогда для 0,1 .. если в 2- то 0,2. Вот почему внутренний подзапрос соединения действительно идет и находит эти значения так, как он делает. – Maris

+0

Подзапрос фактически возвращает мне всегда три строки с двумя столбцами: id_group, maxdate. id_group всегда 0,1,2, а maxdate вычисляется для (0 и 1 и 2) (0 и 1) (0 и 2) – Maris

ответ

1

Хорошо, я надеюсь, я понял ваш первоначальный SQL в настоящее время. Вы хотите, чтобы все GC с последней подходящей максимальной датой. То, что вы считаете подходящим, зависит как от gc.dt_lastused, так и от gc.id_group. Таким образом, вместо того, чтобы присоединиться таблицы вместе, вы должны выбрать максимальную дату для каждой записи в подзапрос:

select id, 
(
    select max(dt_active_to) 
    from gcdeals 
    where dt_active_from > gc.dt_lastused and dt_active_from <= @now 
    and 
    (
    gc.id_group = 0) 
    or 
    (gc.id_group = 1 and gcdeals.id_group <> 2) 
    or 
    (gc.id_group = 2 and gcdeals.id_group <> 1) 
) 
) as maxdate 
from gc 
where is_active = 1 and dt_lastused < @now 
and id not in (select id_gc from gcmsg) 
order by id; 

EDIT: Вот то же самое утверждение с использованием соединения, предлагая выбрать макс (dt_active_from) и мин (dt_active_to) за один проход:

select gc.id, max(gcd.dt_active_from), min(gcd.dt_active_to) 
from gc 
left outer join gcdeals gcd 
    on gc.id = gcd.id_gc 
    and gcd.dt_active_from > gc.dt_lastused and gcd.dt_active_from <= @now 
    and 
    (
    gc.id_group = 0) 
    or 
    (gc.id_group = 1 and gcd.id_group <> 2) 
    or 
    (gc.id_group = 2 and gcd.id_group <> 1) 
) 
where gc.is_active = 1 and gc.dt_lastused < @now 
group by gc.id 
order by gc.id; 

вы видите, как только вы узнали, как выбрать нужное значение в подзапрос, это не слишком сложно, чтобы изменить его в соединение. Вы получаете то, что ищете в два этапа. Если, с другой стороны, вы начинаете с мышления в объединении, одна и та же задача может быть довольно абстрактной.

Что касается плана выполнения: Скажем, GC имеет 1000 активных записей, и в GCDeals обычно имеется около 10 соответствующих совпадений. Затем первый оператор выбирает 1000 записей и использует цикл для каждой записи для доступа к совокупному значению GCDeals. Второе утверждение просто присоединилось бы к 1000 записям GC с 10 записями GCDeals каждый, таким образом получив 10 000 записей, а затем объединит их, чтобы сделать 1000 записей снова. Возможно, петли быстрее, возможно, соединение. Это зависит. Но, скажем, GC имеет миллион активных записей, и на каждой записи вы ожидаете соответствия 1000 GCDeals, тогда первый оператор может быть довольно медленным, чтобы цикл был так много раз. Но второй оператор создаст миллиардные промежуточные записи, которые могут вызвать проблемы с памятью и либо привести к очень медленному выполнению, либо даже привести к недопустимой ошибке памяти. Так что просто хорошо знать, что доступны оба метода.

+0

Спасибо, дадут эту попытку и посмотрим, будет ли это работать или нет :) Пальцы пересеклись – Maris

+0

Это действительно работает .. за исключением одного небольшого недостающего "(" что здесь, конечно, не имеет значения. логики, стоящие за этим .. да, совершенно другое мышление, чем мой первоначальный подход. Большое спасибо и по-настоящему ценю ваше время! – Maris

+0

Еще один вопрос ... если я хотел бы изменить начало запроса следующим образом: SELECT id, ( SELECT MAX (dt_active_from), MIN (dt_active_to) ... это не позволит мне, конечно. Было бы уместно включить две идентичные конструкции для извлечения MAX (dt_active_from) и еще одного для MIN (dt_active_to)? Может быть, производительность сильно пострадает? – Maris

Смежные вопросы