Использование DATEDIFF в T-SQL

Кажется, переопределение метода инициализации сработало для меня. Например,

setClass("Person",
         representation(name = "character", age = "numeric", doubleAge = "numeric"),
         prototype(name = "Bob", age = 5, doubleAge = 10) )

setMethod("initialize", "Person", function(.Object, ...) {
  .Object <- callNextMethod()
  .Object@doubleAge <- .Object@age*2
  .Object
})

(p1 <- new("Person", name = "Alice", age = 6))
# An object of class "Person"
# Slot "name":
# [1] "Alice"
# Slot "age":
# [1] 6
# Slot "doubleAge":
# [1] 12

callNextMethod() запускает инициализатор «по умолчанию», чтобы установить все значения, с которыми мы не связываемся. Затем мы просто изменяем нужные значения и возвращаем обновленный объект.

6
задан Josh Stodola 15 May 2009 в 18:38
поделиться

5 ответов

Вы можете ' t обращаются к столбцам, определенным в операторе select в операторе where, потому что они не создаются до тех пор, пока не будет выполнено where.

Вы можете сделать это, однако

select InitialSave from 
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10

В качестве примечания - это по существу перемещает DATEDIFF в оператор where в терминах того места, где он был определен впервые. Использование функций для столбцов в операторах where приводит к снижению эффективности использования индексов, и этого следует по возможности избегать, однако, если вам нужно использовать dateiff, вы должны это сделать!

5
ответ дан 8 December 2019 в 13:02
поделиться

помимо "работы", вам нужно использовать индекс

, использовать вычисляемый столбец с индексом или представление с индексом, иначе вы будете сканировать таблицу. когда у вас будет достаточно строк, вы почувствуете БОЛЬ медленного сканирования!

вычисленный столбец и индекс:

ALTER TABLE MyTable ADD
    ComputedDate  AS DATEDIFF(ss,BegTime, EndTime)
GO
CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate  ON MyTable 
    (
    ComputedDate
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

создать представление и индекс:

CREATE VIEW YourNewView
AS
SELECT
    KeyValues
        ,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable
GO
CREATE CLUSTERED INDEX IX_YourNewView
    ON YourNewView(InitialSave)
GO
3
ответ дан 8 December 2019 в 13:02
поделиться

Примечание: Когда я изначально писал этот ответ, я сказал, что индекс в одном из столбцов может создать запрос, который работает лучше, чем другие ответы (и упомянул Дэна Фуллер). Однако я не думал на все 100% правильно. Дело в том, что без вычисляемого столбца или индексированного (материализованного) представления потребуется полное сканирование таблицы , потому что два сравниваемых столбца даты взяты из той же таблицы!

Я считаю, что информация ниже по-прежнему имеет значение, а именно: 1) возможность повышения производительности в правильной ситуации, например, когда выполняется сравнение между столбцами из разных таблиц, и 2) продвижение привычки разработчиков SQL следовать лучшим практиковать и менять свое мышление в правильном направлении.

Сделать условия доступными

Наилучшая практика, о которой я говорю, - это перемещение одного столбца в одиночку с одной стороны от оператора сравнения, например:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'

Как я сказал, это не предотвратит сканирование на одной таблице, однако, в такой ситуации это может иметь огромное значение:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
   dbo.BeginTime B
   INNER JOIN dbo.EndTime E
      ON B.BeginTime <= E.EndTime
      AND B.BeginTime + '00:00:10' > E.EndTime

EndTime теперь находится в обоих условиях только на одной стороне сравнения. Если предположить, что таблица BeginTime имеет намного меньше строк, а таблица EndTime имеет индекс по столбцу EndTime , это будет работать намного, намного лучше, чем что-либо, использующее DateDiff (второй, B.BeginTime, E.EndTime) . Теперь это sargable , что означает, что существует допустимый «аргумент поиска» - так как машина сканирует таблицу BeginTime , он может искать в таблице EndTime . Требуется тщательный выбор того, какой столбец находится отдельно от оператора - может быть стоит поэкспериментировать, поместив BeginTime отдельно, выполнив некоторую алгебру для переключения на И B.BeginTime> E .EndTime - '00: 00: 10 '

Точность DateDiff

Я также должен отметить, что DateDiff не возвращает прошедшее время, а вместо этого подсчитывает количество границы пересеклись. Если вызов DateDiff с использованием секунд возвращает 1 , это может означать 3 мс прошедшего времени или 1997 мс ! По сути, это точность + - 1 единицы времени. Для большей точности ± 1/2 единицы времени, вам нужен следующий запрос, сравнивающий 0 с EndTime - BegTime :

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

Теперь максимальная ошибка округления составляет всего одну секунду, а не две (фактически, пол ( ) операция). Обратите внимание, что вы можете только вычесть тип данных datetime - чтобы вычесть значение date или time , которое необходимо преобразовать в datetime ] или используйте другие методы для повышения точности (целое множество DateAdd , DateDiff и, возможно, другой мусор, или, возможно, с использованием более точных единиц времени и деления).

Этот принцип особенно важен при подсчете более крупных единиц, таких как часы, дни или месяцы. Разница в DateDiff из 1 месяц может составлять 62 дня (предположим, с 1 июля 2013 г. по 31 августа 2013 г.)!

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

Теперь максимальная ошибка округления составляет всего одну секунду, а не две (фактически, операция floor ()). Обратите внимание, что вы можете только вычесть тип данных datetime - чтобы вычесть значение date или time , которое необходимо преобразовать в datetime ] или используйте другие методы для повышения точности (целое множество DateAdd , DateDiff и, возможно, другой мусор, или, возможно, с использованием более точных единиц времени и деления).

Этот принцип особенно важен при подсчете более крупных единиц, таких как часы, дни или месяцы. Разница в DateDiff из 1 месяц может составлять 62 дня (предположим, 1 июля 2013 г. - 31 августа 2013 г.)!

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

Теперь максимальная ошибка округления составляет всего одну секунду, а не две (фактически, операция floor ()). Обратите внимание, что вы можете только вычесть тип данных datetime - чтобы вычесть значение date или time , которое необходимо преобразовать в datetime ] или используйте другие методы для повышения точности (целое множество DateAdd , DateDiff и, возможно, другой мусор, или, возможно, с использованием более точных единиц времени и деления).

Этот принцип особенно важен при подсчете более крупных единиц, таких как часы, дни или месяцы. Разница в DateDiff из 1 месяц может составлять 62 дня (предположим, 1 июля 2013 г. - 31 августа 2013 г.)!

Обратите внимание, что вы можете только вычесть тип данных datetime - чтобы вычесть значение date или time , которое необходимо преобразовать в datetime ] или используйте другие методы, чтобы получить лучшую точность (много DateAdd , DateDiff и, возможно, другой мусор, или, возможно, с использованием более точных единиц времени и деления).

Этот принцип особенно важен при подсчете более крупных единиц, таких как часы, дни или месяцы. Разница в DateDiff из 1 месяц может составлять 62 дня (предположим, с 1 июля 2013 г. по 31 августа 2013 г.)!

Обратите внимание, что вы можете только вычесть тип данных datetime - чтобы вычесть значение date или time , которое необходимо преобразовать в datetime ] или используйте другие методы, чтобы получить лучшую точность (много DateAdd , DateDiff и, возможно, другой мусор, или, возможно, с использованием более точных единиц времени и деления).

Этот принцип особенно важен при подсчете более крупных единиц, таких как часы, дни или месяцы. Разница в DateDiff из 1 месяц может составлять 62 дня (предположим, с 1 июля 2013 г. по 31 августа 2013 г.)!

7
ответ дан 8 December 2019 в 13:02
поделиться

Запуск потоков в конструкторах, которые запускают код в еще строящемся объекте, опасен. Представленный вами код будет работать правильно, как есть, но решение хрупкое.

Если DoCallback вызывает виртуальный метод в A , то вы можете получить неожиданные результаты в зависимости от того, насколько быстро выполняется поток. Если вызываемый метод является чисто виртуальным, приложение умрет, если он не является чистым, вместо производной версии будет вызываться A версия метода. По этой же причине вы никогда не должны вызывать виртуальный метод из конструктора.

Более безопасный подход - это когда пользователь вызывает поток. Такой же подход используется в библиотеке boost :: thread и в будущем стандарте.

2
ответ дан 8 December 2019 в 13:02
поделиться

В качестве альтернативы вы можете использовать вычисляемые столбцы .

1
ответ дан 8 December 2019 в 13:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: