У каждого из моих клиентов может быть много задач, и у каждой задачи есть срок выполнения.
Каков будет запрос для обнаружения следующего отмененного элемента задачи по сроку для каждого файла? Если у клиента более одного дела, то правильным будет тот, у которого самый низкий идентификатор.
Предполагая следующую минимальную схему:
clients (id, name)
todos (id, client_id, description, timestamp_due, timestamp_completed)
Спасибо.
Я использую SQL Server, но специально его не упомянул. Я бы предпочел прямое решение SQL.


Следующее должно вас приблизить, сначала получите минимальное время для каждого клиента, затем найдите информацию о клиенте / задачах.
SELECT
C.Id,
C.Name,
T.Id
T.Description,
T.timestamp_due
FROM
{
SELECT
client_id,
MIN(timestamp_due) AS "DueDate"
FROM todos
WHERE timestamp_completed IS NULL
GROUP BY ClientId
} AS MinValues
INNER JOIN Clients C
ON (MinValues.client_id = C.Id)
INNER JOIN todos T
ON (MinValues.client_id = T.client_id
AND MinValues.DueDate = T.timestamp_due)
ORDER BY C.Name
ПРИМЕЧАНИЕ: Написано в предположении SQL Server
SELECT c.name, MIN(t.id)
FROM clients c, todos t
WHERE c.id = t.client_id AND t.timestamp_complete IS NULL
GROUP BY c.id
HAVING t.timestamp_due <= MIN(t.timestamp_due)
Избегает подзапросов, коррелированных или иных, но вводит набор агрегированных операций, которые не намного лучше.
Используем синтаксис sqlite, но ничего особенного.
Это не сработает в SQL Server, поскольку группа по не содержит столбцов Name и Description.
Это предполагает, что идентификаторы представляют хронологию, а это не так.
Вопрос явно запрашивает самый низкий идентификатор.
Вопрос явно запрашивает наименьший идентификатор в случае привязанной даты.
Имея -перед- группировку? Странные вещи.
Это классический вопрос выбор победителя для каждой группы. Он публикуется примерно два раза в день.
SELECT *
FROM todos t
WHERE t.timestamp_completed is null
and
(
SELECT top 1 t2.id
FROM todos t2
WHERE t.client_id = t2.client_id
and t2.timestamp_completed is null
--there is no earlier record
and
(t.timestamp_due > t2.timestamp_due
or (t.timestamp_due = t2.timestamp_due and t.id > t2.id)
)
) is null
Некоторый Jet SQL, я понимаю, маловероятно, что спрашивающий использует Jet, как бы читатель ни был.
SELECT c.name, t.description, t.timestamp_due
FROM (clients c
INNER JOIN
(SELECT t.client_id, Min(t.id) AS MinOfid
FROM todos t
WHERE t.timestamp_completed Is Null
GROUP BY t.client_id) AS tm
ON c.id = tm.client_id)
INNER JOIN todos t ON tm.MinOfid = t.id
Я еще не тестировал это, поэтому вам, возможно, придется его настроить:
SELECT
TD1.client_id,
TD1.id,
TD1.description,
TD1.timestamp_due
FROM
Todos TD1
LEFT OUTER JOIN Todos TD2 ON
TD2.client_id = TD1.client_id AND
TD2.timestamp_completed IS NULL AND
(
TD2.timestamp_due < TD1.timestamp_due OR
(TD2.timestamp_due = TD1.timestamp_due AND TD2.id < TD1.id)
)
WHERE
TD2.id IS NULL
Вместо того, чтобы пытаться сортировать и агрегировать, вы в основном отвечаете на вопрос: «Есть ли еще какие-нибудь задачи, которые предшествуют этой?» (на основе вашего определения «до»). Если нет, то это то, что вам нужно.
Это должно быть действительным на большинстве платформ SQL.
Это мое любимое решение такого рода проблем. Я много раз размещал его в SO и других новостных группах. Он не использует ни подзапросов, ни GROUP BY, ни синтаксиса, проприетарного поставщика.
Вы не сказали, какую платформу вы используете - разные платформы имеют разный синтаксис.