#sql #date #ms-access
#sql #Дата #ms-access
Вопрос:
У меня проблема, которую я просто не могу понять. У меня есть список сотрудников с разными датами поездок, и я хочу отобразить их все в формате каскадного списка. Проблема в том, что я хочу видеть сотрудников только один раз и только дату, ближайшую к сегодняшнему дню.
Например, я мог бы иметь «Smith» там несколько раз с датами до и после сегодняшнего дня, поскольку мы также ведем исторические записи. Это означает, что я не могу просто выполнить min, так как он попытается отобразить дату до сегодняшнего дня, а max слишком далеко вперед.
Приведенный ниже пример кода ПОЧТИ работает. Проблема заключается в инструкции select. Я хочу показать минимальную дату после сегодняшнего дня, но вместо этого она дает мне 0 и -1, где должны быть даты. Возможно, есть другой способ сделать все это вместе, но это единственная конфигурация, которая, по-видимому, позволяет корректно отображать рядом с ней другую информацию, такую как сайт, позиция и комментарии.
SELECT A.`Last Name` AS [Last Name], Min(A.`Date In`) > Now() AS [Date In], Max(B.Site) AS Site, Max(B.Position), Max(B.Comments) AS Comments
FROM Deployments AS A
INNER JOIN Deployments AS B ON A.ID = B.ID
GROUP BY A.`FSR Name`
HAVING (((Max(A.`Actual TEP IN`))>Now()));
Я создал группу по имени, потому что хочу видеть каждого человека только один раз. Если я не добавляю таблицу к себе с помощью join, это выдает ошибку ссылки на себя. Это моя первая публикация, поэтому я надеюсь, что это имеет смысл! Любая помощь будет принята с благодарностью!
Комментарии:
1. Какую базу данных вы используете? Вы смешиваете соглашения SQL Server / Sybase с соглашениями MySQL. Кроме того, почему вы выполняете самосоединение. Это не имеет смысла.
2. Извините, что я использую MS Access
Ответ №1:
Не уверен, в какой базе данных вы работаете, но в целом вам нужно возвращать MIN (date) вместо результата сравнения «Min (Date)> Now ()» — я предполагаю, что именно здесь вы видите 0 и -1, поскольку это было бы результатомсравнение, когда вам нужно минимальное значение даты.
Кроме того, если вам просто нужны люди, у которых есть дата поездки в будущем, просто ограничьте свой запрос предложением WHERE, выполните GROUP BY, и вы избавитесь от самосоединения. Также обратите внимание, что приведенный ниже пример выравнивает некоторые расхождения в вашей операции, например, когда вы выбираете на основе «Фамилии», но группируете по «FSR Name» — эти вещи должны быть согласованы, в зависимости от того, какое поле вас интересует.
Пример:
SELECT A.[FSR Name] AS [FSR Name],
Min(A.[Date In]) AS [Date In],
Max(A.Site) AS Site,
Max(A.Position) AS Position,
Max(A.Comments) AS Comments
FROM Deployments AS A
WHERE A.[Date In] > Now()
GROUP BY A.[FSR Name];
РЕДАКТИРОВАТЬ: если вам нужно убедиться, что сайт, позиция, комментарии все взяты из одной строки, вам нужно сделать что-то вроде одного из этих вариантов:
Если у вас есть первичный ключ:
select * from Deployments A3 where A3.pk_value =
(select max(A2.pk_value) from Deployments A2
where A2.[Date In] =
(select Max([Date In]) from Deployments A where A.[FSR Name] = A2.[FSR Name])
and A2.[FSR Name] = A3.[FSR Name]
)
Это гарантирует получение 1 строки для каждого имени FSR, даже если для этого FSR имеется несколько строк с одной и той же «последней» датой.
В противном случае вы можете не использовать вторичный запрос, имеющий дело с значением pk_value, но вы рискуете получить несколько строк для FSR, который содержит несколько записей с одной и той же «последней» датой.
Примечание: когда вы добираетесь до таких сложных запросов, запуск полнофункциональной базы данных (SQL Server, Oracle, что угодно, кроме Access) позволяет использовать гораздо более сложные возможности. В этом примере «Оконные функции» дадут вам ответ без особых споров. Не уверен, что вы застряли с Access на данный момент, но в любом случае учтите это на будущее.
Комментарии:
1. Я переформатировал следующим образом: «ВЫБЕРИТЕ «Фамилия» КАК [Фамилия], Min (
Date In
) КАК [Дата в], Max (сайт) КАК сайт, Max (позиция) КАК позиция, Max (Комментарии) ПОСКОЛЬКУ комментарии ИЗ Deployments ГРУППИРУЮТСЯ ПОLast Name
WHEREDate In
> Now(); ‘ Но это выдает мне эту ошибку — «Синтаксическая ошибка (пропущенный оператор) в выражении запроса ‘Last Name
WHEREDate In
> Now()’. Также я прошу прощения, но я понятия не имею, как отформатировать комментарий, чтобы он выглядел лучше.2. Изначально у меня был WHERE, следующий после GROUP BY, что могло вызвать синтаксическую ошибку. Теперь это исправлено в приведенном выше ответе. Извините!
3. Хм, это становится ближе! Теперь он сообщает мне, что у меня есть циклическая ссылка с сайтом, позицией и комментариями. Я заметил в вашем ответе, что у вас все еще есть развертывания КАК A, но нет развертываний КАК B. Должно ли это быть там снова? РЕДАКТИРОВАТЬ: я вставил это, и это сработало! Единственная странность заключается в том, что Access запрашивает имя и дату, когда я выполняю запрос, и если я ничего не ввожу, он выводит правильную информацию. Интересно, как бы я сделал так, чтобы он не запрашивал ввода?
4. @user3779582 Я отредактировал, так что единственным псевдонимом таблицы теперь является «A». Что касается запроса Access, возможно, это связано с одинарными кавычками вокруг имен полей? Вы можете попробовать использовать квадратные скобки или двойные кавычки. Некоторые базы данных обрабатывают имена полей по-разному, и доступ к ним отличается от большинства.
5. О, я только что столкнулся с проблемой @SlimsGhost, он не отображает правильные поля сайта / позиции / комментариев. Сейчас они не связываются должным образом.
Ответ №2:
Попробуйте что-то вроде этого
Select A.LastName, A.DateIn, A.Site, A.Position, A.Comments
From deployments a
Where not exists (Select *
From deployments b
Where b.id <> a.id
and (abs(datediff(d, getdate(), a.datein))) > abs(datediff(d, getdate(), b.datein))
or abs(datediff(d, getdate(), a.datein)) = abs(datediff(d, getdate(), b.datein) and a.id > b.id))
Вместо забавных минимальных и максимальных значений, которые вы используете, чтобы попытаться получить строку с датой, которая ближе всего к сегодняшнему дню, попробуйте использовать datediff . С помощью этой функции вы можете указать, какой тип значения даты или времени вы хотите сравнить (день, месяц, год, минута), а затем найти разницу между двумя разными датами. В этом случае я использовал getdate() для поиска текущей даты и времени. Затем нам нужна дата с наименьшим значением для datediff, дата, которая ближе всего к сегодняшнему дню. Datediff вернет положительные или отрицательные значения, поэтому я использовал abs для получения абсолютного значения результата. Я сделал это, потому что не имеет значения, указана ли дата до сегодняшнего дня или после сегодняшнего дня.
Затем мы смотрим в таблицу развертывания. В подзапросе говорится, что мы должны просмотреть все значения, которые не являются текущими. Затем найдите все строки, которые имеют меньший datediff, чем текущая запись. Кроме того, найдите все записи, которые имеют тот же datediff, что и текущая запись, и меньший идентификатор. Мы включим текущую запись только в том случае, если нет ничего, что соответствует этим критериям. Об этом немного странно думать, но этот тип запроса должен помочь вам найти то, что вы ищете, намного проще. Единственное, что вам нужно будет добавить критерии в предложение where подзапроса, чтобы определить, какие записи сравнивать. В нынешнем виде этот запрос просмотрит все записи в вашей таблице deployments и извлечет одну строку, дата которой ближе всего к сегодняшнему дню. Поскольку вам нужна одна строка для каждого пользователя, для этого потребуется еще несколько спецификаций.
Комментарии:
1. Хм, я попробовал это сделать, но выдает ошибку, указывающую, что ее слишком сложно оценить или она введена неправильно. Я также не уверен, будет ли он соответствующим образом связывать сайт / позицию / комментарии.
2. @user3779582 Просто посмотрел на это еще раз, мне определенно не хватало нескольких скобок. Как объясняется в моем ответе, вам нужно будет добавить несколько вещей в предложение where подзапроса. Я не был уверен, что такое «идентификатор». Если у вас есть несколько записей для Smith, имеет ли каждая запись свой собственный идентификатор или они все одинаковые?
3. К сожалению, база данных, с которой я имею дело, использует естественные ключи в виде фамилии. Так что да, каждый идентификатор для каждой записи отличается. Проблема, с которой я сталкиваюсь, заключается в том, что я просто не могу сопоставить эти две вещи даже с ответами других людей. Я не могу понять логику этого, даже если я использую упрощенные подходы. Я бы подумал, что, имея A.ID = B.ID было бы достаточно, но я думаю, что нет?
4. @user3779582 но если каждый идентификатор уникален, то установка одинаковых идентификаторов означает, что вы дважды извлекаете одну и ту же запись, а не все записи для одного человека. Разве не имело бы больше смысла сопоставлять A и B по их естественным ключам?