Как выбрать отличное от максимального здесь

У меня есть следующая таблица A и таблица B, где A один ко многим с B; для каждой записи A мне нужно выбрать соответствующую максимальную запись в B для каждой группы для A. т.е. группировка выполняется на основе last_updated_time.

SELECT taba.ws_name, tabb.b2a,  max(tabb.last_update_time)
FROM TabA taba, TabB tabb
where taba.name = 'xyz'
and taba.id = tabb.b2a 
group by taba.ws_name, tabb.b2a 

Это работает хорошо и хорошо.

Проблема возникает, когда мне нужно выбрать «статус» последней транзакции, это приводит к выбору дубликатов, потому что статус может быть либо неудачным, либо успешным.

Мое требование — выбрать только максимальную запись независимо от ее статуса (хотя мне также нужно отобразить статус)

Поэтому, когда какое-либо «ws_name» имеет несколько записей об ошибках, а также об успехах, поэтому MAX updated_time выбирается для обеих групп («Неудача» и «Успех»).

Ниже приведен запрос, который я пробовал и не понял, как удалить дубликаты, выбранные из-за статуса.

SELECT taba.ws_name, tabb.b2a, **tabb.status**,  max(tabb.last_update_time)
FROM TabA taba, TabB tabb
where taba.name = 'xyz'
and taba.id = tabb.b2a 
group by taba.ws_name, tabb.b2a, **tabb.status**

person sid    schedule 10.01.2012    source источник
comment
Мой SQL мозг отключился на тот день, когда я пришел домой с работы, но у вас просто выбор, а не группировка по tabb.status выдает ошибку?   -  person Joachim Isaksson    schedule 11.01.2012
comment
@JoachimIsaksson зависит от типа сервера. Строгий сервер, такой как postgres, взорвется. Нестрогие серверы, такие как mysql, не будут - в mysql может быть возвращена первая строка, встречающаяся для каждой группы.   -  person Bohemian♦    schedule 11.01.2012


Ответы (3)


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

Например:

SELECT     InnerQuery.*,
           TabB.Status

FROM      
            (SELECT     A.ws_name, 
                       B.b2a, 
                       max(B.last_update_time) AS MaxUpdatedTime

            FROM       TabA A
            INNER JOIN TabB B ON (A.id = B.b2a)

            GROUP BY   A.ws_name,
                              B.b2a) AS InnerQuery
INNER JOIN
            TabB ON (InnerQuery.b2a = TabB.b2A AND TabB.last_update_time = InnerQuery.MaxUpdatedTime)

InnerQuery дает вам все строки, которые вы хотите, кроме без статуса. Поэтому мы присоединяемся обратно к B, чтобы получить статус совпадающих строк.

то есть мы получаем все строки в B, которые мы хотим, затем присоединяемся обратно к B, чтобы получить значение статуса для тех строк, которые мы однозначно идентифицировали, потому что, как вы говорите, введение статуса просто дает нам еще один уровень группировки.

person dash    schedule 10.01.2012
comment
спасибо, мне пришлось добавить «отличный» в первый выбор, потому что «MaxUpdatedTime» иногда имеет одинаковые значения для нескольких, и, следовательно, здесь также возвращались дубликаты на основе максимального времени. - person sid; 11.01.2012

Вам нужно иметь вложенный SELECT:

SELECT
    X.*, B.status
FROM
    (SELECT
        taba.ws_name,
        tabb.b2a,
        max(tabb.last_update_time) AS maxtime
     FROM
        TabA taba,
        TabB tabb
     where
        taba.name = 'xyz' and taba.id = tabb.b2a
     group by
        taba.ws_name,
        tabb.b2a) X,
    tabb B
WHERE
    X.b2a = B.b2a AND X.maxtime = B.last_update_time

Я бы также использовал предложения соединения. Это «современный» способ соединения таблиц.

SELECT
    X.*, Y.status
FROM
    ( SELECT
          A.ws_name,
          B.b2a,
          max(B.last_update_time) AS maxtime
      FROM
          TabA A
          INNER JOIN TabB B
              ON A.id = B.b2a
      WHERE
          A.name = 'xyz'
      GROUP BY
          A.ws_name,
          B.b2a) X,
    INNER JOIN TabB Y
        ON X.b2a = Y.b2a AND X.maxtime = Y.last_update_time

Если вы замените «INNER JOIN» на «LEFT JOIN», вы также получите результаты для записей в TabA, когда в TabB нет соответствующих записей.

person Olivier Jacot-Descombes    schedule 10.01.2012

Вы можете использовать CTE, на самом деле для этого случая будет тот же результат, используя this и подзапросы, но разница в том, что (на мой взгляд) этот код легче читать.

Первый блок (WITH) выполняет запрос для получения максимальных значений и соответствующих им идентификаторов и сохраняет результаты во «временной таблице».

Затем во втором запросе используйте максимальные значения, полученные в результате запроса CTE (первого), и используйте их для ограничения результатов исходного запроса.

WITH TabB_CTE(b2a, last_update_time) as
(
    Select
        b2a, max(last_update_time) As last_update_time
    From
        TabB
    Group By b2a
)

SELECT 
    taba.ws_name, tabb.b2a, tabb.status, tabb.last_update_time
FROM
    TabA taba Join TabB tabb
        On  taba.id = tabb.b2a
    Join TabB_CTE tabc
        On  tabc.b2a = tabb.b2a
        And tabc.last_update_time = tabb.last_update_time
where taba.name = 'xyz'
person alsm    schedule 10.01.2012