Я думаю, что следующее должно работать почти во всех продуктах SQL:
SELECT
cGift.gidnumb,
cGift.id,
cGift.date,
first.isfirst
FROM cGift
LEFT JOIN (
SELECT id, MIN(date) AS date, 't' AS isfirst
FROM cGift
GROUP BY id
) first ON cGift.id = first.id AND cGift.date = first.date
ОБНОВЛЕНИЕ (с учетом дополнительных критериев):
Если человек может сделать пожертвование более чем один раз на MIN(date)
, и вы хотите, чтобы только одно пожертвование было отмечено t
, вы можете, например, сделать это:
SELECT
cGift.gidnumb,
cGift.id,
cGift.date,
first.isfirst
FROM cGift
LEFT JOIN (
SELECT
MIN(g.gidnumb) AS g.gidnumb,
g.id,
g.date,
't' AS isfirst
FROM cGift g
INNER JOIN (
SELECT id, MIN(date) AS date
FROM cGift
GROUP BY id
) f ON g.id = f.id AND g.date = f.date
GROUP BY g.id, g.date
) first ON cGift.id = first.id AND cGift.date = first.date
То есть самый внутренний запрос находит минимальные дни для каждого человека, как и в предыдущем решении, но затем он также детализирует список с конкретными значениями gidnumb
, гарантируя, что только одна строка на человека будет соответствовать этому списку в cGift
Таблица.
Этот запрос должен по-прежнему выполняться в любой СУБД. Это может быть менее эффективным, учитывая двойную группировку. Вот альтернатива, которая также использует только стандартный SQL, без специфических для поставщика функций (он также должен быть немного более гибким, чем предыдущий запрос):
SELECT
gidnumb,
id,
date,
CASE
WHEN NOT EXISTS (
SELECT *
FROM cGift
WHERE id = g.id
AND (
date < g.date OR
date = g.date AND gidnumb < g.gidnumb
)
)
THEN 't'
END AS isfirst
FROM cGift g
Как видите, столбец isfirst
вычисляется с помощью самопроверки таблицы: если в этой таблице нет строки с таким же id
и более ранней датой или, если дата совпадает, меньше gidnumb
, эта строка должна быть помечена как t
. При отсутствии ELSE
часть CASE
подразумевается ELSE NULL
. Вы можете, если хотите, добавить что-то вроде ELSE 'f'
.
Тем не менее, ваш продукт SQL может обладать функциями, которые вы могли бы получить, создав, возможно, более простой и эффективный запрос. Некоторые продукты, например, поддерживают функции ранжирования (которые уже являются частью стандарта SQL, просто они еще не поддерживаются повсеместно), и вот что вы можете сделать с помощью функции ранжирования ROW_NUMBER()
:
SELECT
gidnumb,
id,
date,
CASE ROW_NUMBER() OVER (PARTITION BY id ORDER BY date, gidnumb)
WHEN 1
THEN 't'
END AS isfirst
FROM cGift g
Этот запрос ранжирует строки, разделяя их по id
и сортируя сначала по date
, затем по gidnumb
. Каждая строка с рейтингом 1
в этом случае становится той, которую следует отличать с t
.