У меня есть следующий запрос:
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".
Есть ли способ использовать DISTINCT вместо предложения GROUP?
В конечном счете, мне нужно вернуть одну определенную строку (все столбцы) из 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)
Можно ли это сделать в одном сложном запросе?
Я бы сделал запрос следующим образом:
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, у которых не было соответствия.
Вы можете использовать предложение 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, я также заменил бы "*" фактическим списком полей, которые вы хотите вернуть запросу.