Как да изберете различен от максимума тук

Имам следната таблица 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
благодаря, трябваше да добавя "distinct" в първия избор, защото "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, всъщност за този случай е същият резултат, използвайки това и подзаявки, но разликата е, че (по мое собствено мнение) този код е по-лесен за четене.

Първият блок (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