Вложенный запрос, который извлечет последнюю строку в сгруппированном результате

0

У меня есть следующий запрос:

 SELECT * from 'provider_info' where provnum not in 
 (select pi_provnum from prov_index where length(pi_provnum)=6)
 and length(provnum)=6 group by provnum

prov_index будет иметь только одну строку на provnum/pi_provnum. Но provider_info может иметь несколько строк на provnum.

Я в основном вытягиваю строки из одной таблицы, у которых нет записи провайдера (provnum/pi_provnum) во второй таблице. Внутренний запрос дает мне список столбцов provnum, которые существуют в таблице provider_info, но не существуют в таблице prov_index. (условия length() - это дополнительные вещи, которые мне нужны в запросе)

Поскольку в provider_info может быть несколько записей с одним и тем же провайдером, я использую предложение "group by provnum", чтобы дать мне только один экземпляр. Но в конечном итоге мне нужны все столбцы, соответствующие строке с последним значением "sourcedate".

  1. Есть ли способ использовать DISTINCT вместо предложения GROUP?

  2. В конечном счете, мне нужно вернуть одну определенную строку (все столбцы) из provider_info, то есть строку с последней датой в столбце "soucedate"

Я пробовал это, но он не работает:

 SELECT * from 'provider_info' where provnum not in 
 (select pi_provnum from prov_index where length(pi_provnum)=6) 
 and length(provnum)=6 order by provnum,sourcedate desc group by provnum 
 having sourcedate=max(sourcedate)

В основном, я хочу, это список из одной строки из provider_info, у которой есть последний столбец sourcedate, где provnum не существует во второй таблице prov_index. Ключ я хочу, чтобы все столбцы в последней строке, а не просто макс (sourcedate)

Можно ли это сделать в одном сложном запросе?

  • 0
    Возможно, вы сможете использовать порядок и ограничение для фильтра ... Выберите * из списка provider_info по пределу источника 1
  • 0
    См. Meta.stackoverflow.com/questions/333952/…
Показать ещё 1 комментарий
Теги:
mariadb
greatest-n-per-group

2 ответа

0

Я бы сделал запрос следующим образом:

 SELECT p.*
   FROM
        ( -- latest sourcedate for each provnum
          SELECT s.provnum
               , MAX(s.sourcedate) AS latest_sourcedate
            FROM 'provider_info' s
           WHERE LENGTH(s.provnum) = 6
           GROUP
              BY s.provnum
        ) q

     -- row(s) that matches latest sourcedate
   JOIN 'provider_info' p
     ON LENGTH(p.provnum) = 6
    AND p.provnum         = q.provnum
    AND p.sourcedate      = q.latest_sourcedate

     -- anti-join exclude rows that have a match
   LEFT
   JOIN prov_index i
     ON LENGTH(i.pi_provnum) = 6
    AMD i.pi_provnum = p.provnum
  WHERE i.pi_provnum IS NULL

  ORDER BY ...

Позвольте распаковать это немного.

Встроенный просмотр (производная таблица) q дает нам различные значения provnum from provider_info с последним sourcedate для каждого.

Мы можем присоединить этот результат к provider_info и получить строки, которые соответствуют на provnum, и иметь sourcedate, соответствующий latest_sourcedate.

Чтобы исключить строки, я предпочел бы использовать шаблон антисоединения вместо NOT IN. Как это работает, мы делаем внешнее соединение, чтобы найти соответствующие строки из prov_index. Внешнее соединение LEFT вернет все строки с левой стороны, а также совпадения с правой стороны. Хитрость заключается в использовании условия в WHERE, которое исключает строки, которые нашли совпадение. Предикат объединения гарантирует нам, что соответствующие строки будут иметь значение, pi_provnum NULL для pi_provnum. Поэтому, если мы исключаем строки с не-NULL значением, то есть только возвращаемые строки, которые имеют значение NULL для pi_provnum, то, что у нас осталось, это строки из стороны LEFT, у которых не было соответствия.

0

Вы можете использовать предложение NOT EXISTS. Он имеет случай, когда он может возвращать повторяющиеся строки, если у вас есть две записи для одного и того же провайдера в provider_info и один и тот же источник (являющийся последней датой). Если это невозможно в вашем сценарии или если вы захотите, чтобы в этом случае были две строки, это могло бы работать:

SELECT p1.* 
from 'provider_info' p1 where p1.provnum not in 
(select pi_provnum from prov_index where length(pi_provnum)=6) 
and length(p1.provnum)=6
AND NOT EXISTS (
    SELECT * FROM provider_info p2 where p1.provnum = p2.provnum AND p1.sourcedate > p2.sourcedate 
)

Sidenote, я также заменил бы "*" фактическим списком полей, которые вы хотите вернуть запросу.

  • 0
    Спасибо - я собираюсь проверить это и доложить! :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню