SQL-запрос для исключения записей, если он соответствует записи в другой таблице (например, праздничные даты) - PullRequest
8 голосов
/ 03 апреля 2009

У меня есть две таблицы:

Применение
applicationid (int)
имя приложения (varchar)
доступно (бит)

и

Праздники
applicationid (int)
выходной день (дата / время)

Мне нужно получить флаг isavailable для любого заданного имени приложения, но он должен возвращаться только в том случае, если день не является выходным. Флаг isavailable не зависит от праздников - он устанавливается только в случае проблем в системе, а не по заданному расписанию.

У меня изначально было что-то вроде:

select top 1 apps.isavailable
from dbo.Applications apps, dbo.Holidays hol
where apps.applicationid = hol.applicationid and
      apps.applicationname = @appname and
      ((datediff(dd,getdate(),hol.holidaydate)) != 0)

но это возвращало записи, даже если сегодня был выходной, потому что другие даты выходных не совпадают сегодня.

Я пытался

and (CONVERT(VARCHAR,getdate(),101)) not in (CONVERT(VARCHAR,hol.holidaydate,101))

(это на SQL Server 2005, поэтому нет типа Date, поэтому я должен преобразовать его)

но опять же, он возвращал записи, даже если сегодня был выходной. Как я могу структурировать этот запрос, используя предложение «не в» или «кроме» (или что-то еще), чтобы вернуть запись, только если сегодня не выходной?

Обновление

Мне не нужен список всех имен приложений, у которых нет выходных - мне нужна запись для указанного apps.applicationname. Ответы ниже только возвращают названия приложений, на которые сегодня нет выходных. Запрос должен возвращать флаг isavailable, если это не выходной, или же не возвращать никаких записей, если это выходной. Меня не волнуют другие приложения.

Кроме того, что если я добавлю таблицу вроде:

HoursOfOperations
applicationid (int)
понедельникоткрыто (дата / время)
понедельникclose (дата / время)
вторник (дата / время)
вторникclose (дата / время)
// открываем и закрываем все семь дней недели

Могу ли я присоединиться ко всем трем из этих таблиц, чтобы вернуть запись, только если она находится в пределах часов для данного дня и не является выходным? Нужно ли делать это в отдельных запросах?

Ответы [ 6 ]

15 голосов
/ 03 апреля 2009

Следующий запрос должен получить список приложений, для которых НЕ установлен выходной день для ТЕКУЩЕЙ даты.

SELECT apps.ApplicationName, apps.isavailable 
FROM dbo.Applications apps
WHERE apps.ApplicationName = @AppName
    AND NOT EXISTS 
( SELECT * 
  FROM Holidays 
  WHERE ApplicationId = apps.ApplicationId
     AND CONVERT(VARCHAR,getdate(),101) = CONVERT(VARCHAR,holidaydate,101)
)

По сути, мы выбираем все, где нет совпадения.

5 голосов
/ 03 апреля 2009

ОК, просто чтобы быть другим, как на счет этого:

select apps.isavailable
from dbo.Application apps left outer join dbo.Holidays hol
    on apps.applicationid = hol.applicationid
    and convert(varchar(10),getdate(),101) = convert(varchar(10),hol.holidaydate,101)
where apps.applicationname = @appname
    and hol.applicationid is null

По сути, вы объединяете таблицы на основе идентификатора приложения и текущей даты. Поскольку это левое соединение, вы всегда будете получать все приложения, которые соответствуют @appname, тогда вы просто отфильтруете любые результаты, которые соответствуют, исходя из даты выходного дня, являющейся текущей датой. Если предположить, что имя приложения уникально, вы всегда получите одну строку, в которой правая половина объединения равна нулю, если текущая дата не соответствует выходному, в этом случае запрос не даст результатов.

Я не знаю, как это складывается с другими решениями с точки зрения производительности; Я полагаю, что объединения, как правило, должны быть быстрее, чем подзапросы, но это, вероятно, зависит от множества факторов, поэтому YMMV.

4 голосов
/ 03 апреля 2009

Вы можете использовать «ГДЕ НЕ СУЩЕСТВУЕТ»:

SELECT *
FROM Applications a
WHERE NOT EXISTS (
    SELECT * 
    FROM Holidays h
    WHERE h.ApplicationID = a.ApplicationID
        AND HolidayDate = cast(cast(getdate() as int) as datetime)
)

Я выполняю приведение там, чтобы обрезать обратный вызов getdate () до даты. Не проверял этот точный запрос, но я думаю, он сработает за вас.

2 голосов
/ 03 апреля 2009
SELECT a.isAvailable
  FROM Application a
 WHERE NOT EXISTS (
    SELECT TOP 1 0
      FROM Holidays b
     WHERE a.applicationid = b.applicationid
       AND holidaydate = $today
 )
2 голосов
/ 03 апреля 2009

Сделайте что-то вроде этого:

SELECT (fields) FROM Application
WHERE NOT EXISTS
  (SELECT * FROM Holidays
   WHERE ApplicationID = Application.ApplicationID
   AND DAY(getdate()) = DAY(holidaydate) 
   AND MONTH(getdate()) = MONTH(holidaydate)
   AND YEAR(getdate()) = YEAR(holidaydate)
  )

Конечно, было бы намного проще и быстрее с типом данных «DATE» в SQL Server 2008 или если бы вы могли хранить день, месяц, год в «Праздниках» отдельно.

Марк

0 голосов
/ 24 августа 2011

А как насчет этого:

SELECT 
  Application.isavailable
FROM 
   Holidays 
RIGHT JOIN 
   Application
ON 
   Holidays.applicationid = Application.applicationid
WHERE 
  ((Application.applicationname='app1') AND 
  (((Holidays.holidaydate=CurrentDate()) AND (Holidays.applicationid Is Null)) OR 
  (holidays.holidaydate Is Null)));

"'app1'" следует заменить спецификатором переменной, а функцию "CurrentDate ()" - системной функцией для возврата текущей даты.

Приветствия

/ а

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...