Вот мой подход к решению этой проблемы:
- Свяжите каждую дату поиска с датой в таблице.
- Используйте даты поиска в качестве (дополнительных) групповых терминов.
- Ранжируйте даты в порядке убывания, разбивая их по групповым терминам.
- Выберите те, у которых есть нужные значения групповых терминов и
rank = 1
.
Сценарий:
WITH price_grouped AS (
SELECT
date, grp, id, price,
dategrp = CASE
WHEN date <= '11/30/2009' THEN '11/30/2009'
WHEN date <= '12/31/2009' THEN '12/31/2009'
/* extend the list of dates here */
END
FROM price_table
),
price_ranked AS (
SELECT
date, grp, id, price, dategrp,
rank = RANK() OVER (PARTITION BY grp, dategrp ORDER BY date DESC)
FROM price_grouped
)
SELECT date, grp, id, price
FROM price_ranked
WHERE grp IN ('Group1')
AND rank = 1
Приведенное выше решение может показаться не очень удобным из-за необходимости повторять каждую дату поиска дважды. Альтернативой этому может быть определение списка дат поиска как отдельного CTE и, соответственно, присвоение дат другим способом:
WITH search_dates (Date) AS (
SELECT '11/30/2009' UNION ALL
SELECT '12/31/2009'
/* extend the list of dates here */
),
price_grouped AS (
SELECT
p.date, p.grp, p.id, p.price,
dategrp = MIN(d.Date)
FROM price_table p
INNER JOIN search_dates d ON p.date <= d.Date
GROUP BY
p.date, p.grp, p.id, p.price
),
price_ranked AS (
SELECT
date, grp, id, price, dategrp,
rank = RANK() OVER (PARTITION BY grp, dategrp ORDER BY date DESC)
FROM price_grouped
)
SELECT date, grp, id, price
FROM price_ranked
WHERE grp IN ('Group1')
AND rank = 1
Но учтите, что первое решение, скорее всего, будет более производительным.