Чи знаєте ви простий спосіб генерувати один запис за кожну годину за останні 12 годин?


12

У мене є звіт, який показує кількість подій за останні 12 годин, згруповані за годиною. Звучить досить просто, але з чим я борюся - це включити записи, які покривають прогалини.

Ось приклад таблиці:

Event
(
  EventTime datetime,
  EventType int
)

Дані виглядають приблизно так:

  '2012-03-08 08:00:04', 1
  '2012-03-08 09:10:00', 2
  '2012-03-08 09:11:04', 2
  '2012-03-08 09:10:09', 1
  '2012-03-08 10:00:17', 4
  '2012-03-08 11:00:04', 1

Мені потрібно створити набір результатів, який має один запис за кожну годину за останні 12 годин, незалежно від того, були події протягом цієї години чи ні.

Якщо припустити, що поточний час - "2012-03-08 11:00:00", у звіті буде показано (приблизно):

Hour  EventCount
----  ----------
23    0
0     0
1     0
2     0
3     0
4     0
5     0
6     0
7     0
8     1
9     3
10    1

Я придумав рішення, яке використовує таблицю, яка має один запис на кожну годину дня. Мені вдалося отримати результати, які я шукав, використовуючи UNION та деяку складну логіку випадку в пункті де, але я сподівався, що хтось має більш елегантне рішення.

Відповіді:


21

Для SQL Server 2005+ ви можете легко генерувати ці 12 записів за допомогою циклу та рекурсивного CTE. Ось приклад рекурсивного CTE:

DECLARE @Date DATETIME
SELECT @Date = '20120308 11:00:00'

;WITH Dates AS
(
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,@Date)) [Hour], 
      DATEADD(HOUR,-1,@Date) [Date], 1 Num
    UNION ALL
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,[Date])), 
      DATEADD(HOUR,-1,[Date]), Num+1
    FROM Dates
    WHERE Num <= 11
)
SELECT [Hour], [Date]
FROM Dates

Тоді ви просто недіда, щоб приєднати його до таблиці подій.


2
Я знайшов це лише після того, як ви опублікували. objasnextended.com/2009/10/21/… Вказується, що використання CTE для цієї мети є менш ефективним, ніж збережена таблиця. Це правда? Як сказав Нік, це, мабуть, не має значення для цієї справи, але ...
Лей Ріффер

4
Я думаю, що це призведе до зміни більшої кількості рядків, якщо вам потрібно 12 записів, тоді показника не буде хітом
Lamak

Ламак і @swasheck. Хе ... Я трохи запізнююся (втратив слід у цій темі), щоб дістатися до цього, але немає проблем. Дивіться відповідь, яку я нарешті опублікував, щоб підтримати свої вимоги вище. І пам’ятайте, весь код має кумулятивний ефект. Якби всі написані людьми з кодом були "просто" 16 разів швидшими, половина публікацій на таких форумах більше не була б необхідною. І, щоб швидше писати код, не потрібно більше (іноді коротше).
Джефф Моден

10

Таблиці Tally можна використовувати для таких речей. Вони можуть бути дуже ефективними. Створіть таблицю підрахунків нижче. Я створив таблицю з підрахунком лише з 24 рядками для вашого прикладу, але ви можете створити її, скільки б ви хотіли, щоб відповідати іншим цілям.

SELECT TOP 24 
        IDENTITY(INT,1,1) AS N
   INTO dbo.Tally
   FROM Master.dbo.SysColumns sc1,
        Master.dbo.SysColumns sc2

--===== Add a Primary Key to maximize performance
  ALTER TABLE dbo.Tally
    ADD CONSTRAINT PK_Tally_N 
        PRIMARY KEY CLUSTERED (N) WITH FILLFACTOR = 100

Я припустив, що ваша таблиця називається dbo.tblEvents, запустіть запит нижче. Я вважаю, що це те, що ви шукаєте:

SELECT t.n, count(e.EventTime)
FROM dbo.Tally t
LEFT JOIN dbo.tblEvent e  on t.n = datepart(hh, e.EventTime)
GROUP BY t.n
ORDER BY t.n

Я вважаю, що кредит переходить до таких посилань, я вважаю, що саме тут я вперше натрапив на це:

http://www.sqlservercentral.com/articles/T-SQL/62867/

http://www.sqlservercentral.com/articles/T-SQL/74118/


+1, але семантично це таблиця чисел, а не таблиця талі.
Аарон Бертран

1
Одне з визначень "Tally" - це "Порахувати". «Стіл Tally» названий на честь «Палички Tally», яка є довгою худою паличкою, яку звикли рахувати.
Джефф Моден

7

По-перше, мої вибачення за затримку моєї відповіді з моїх останніх коментарів.

Тема з'ясувалася в коментарях, що використання рекурсивного CTE (rCTE звідси далі) працює досить швидко через малу кількість рядків. Хоча це може здатися таким, нічого не може бути далі від істини.

БУДІВАЄТЬСЯ ТАЛЬКО ТАБЛИЧНО ТА ТАКОВО ФУНКЦІЮ

Перш ніж приступити до тестування, нам потрібно побудувати фізичну таблицю Tally з відповідним кластерним індексом та функцією Tally у стилі Ітзік Бен-Гана. Ми також зробимо все це в TempDB, щоб ми випадково не кинули нікого смаку.

Ось код для створення таблиці Tally і моя поточна виробнича версія чудового коду Itzik.

--===== Do this in a nice, safe place that everyone has
    USE tempdb
;
--===== Create/Recreate a Physical Tally Table
     IF OBJECT_ID('dbo.Tally','U') IS NOT NULL
        DROP TABLE dbo.Tally
;
     -- Note that the ISNULL makes a NOT NULL column
 SELECT TOP 1000001
        N = ISNULL(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1,0)
   INTO dbo.Tally
   FROM      sys.all_columns ac1
  CROSS JOIN sys.all_columns ac2
;
  ALTER TABLE dbo.Tally
    ADD CONSTRAINT PK_Tally PRIMARY KEY CLUSTERED (N)
;
--===== Create/Recreate a Tally Function
     IF OBJECT_ID('dbo.fnTally','IF') IS NOT NULL
        DROP FUNCTION dbo.fnTally
;
GO
 CREATE FUNCTION [dbo].[fnTally]
/**********************************************************************************************************************
 Purpose:
 Return a column of BIGINTs from @ZeroOrOne up to and including @MaxN with a max value of 1 Trillion.

 As a performance note, it takes about 00:02:10 (hh:mm:ss) to generate 1 Billion numbers to a throw-away variable.

 Usage:
--===== Syntax example (Returns BIGINT)
 SELECT t.N
   FROM dbo.fnTally(@ZeroOrOne,@MaxN) t
;

 Notes:
 1. Based on Itzik Ben-Gan's cascading CTE (cCTE) method for creating a "readless" Tally Table source of BIGINTs.
    Refer to the following URLs for how it works and introduction for how it replaces certain loops. 
    http://www.sqlservercentral.com/articles/T-SQL/62867/
    http://sqlmag.com/sql-server/virtual-auxiliary-table-numbers
 2. To start a sequence at 0, @ZeroOrOne must be 0 or NULL. Any other value that's convertable to the BIT data-type
    will cause the sequence to start at 1.
 3. If @ZeroOrOne = 1 and @MaxN = 0, no rows will be returned.
 5. If @MaxN is negative or NULL, a "TOP" error will be returned.
 6. @MaxN must be a positive number from >= the value of @ZeroOrOne up to and including 1 Billion. If a larger
    number is used, the function will silently truncate after 1 Billion. If you actually need a sequence with
    that many values, you should consider using a different tool. ;-)
 7. There will be a substantial reduction in performance if "N" is sorted in descending order.  If a descending 
    sort is required, use code similar to the following. Performance will decrease by about 27% but it's still
    very fast especially compared with just doing a simple descending sort on "N", which is about 20 times slower.
    If @ZeroOrOne is a 0, in this case, remove the "+1" from the code.

    DECLARE @MaxN BIGINT; 
     SELECT @MaxN = 1000;
     SELECT DescendingN = @MaxN-N+1 
       FROM dbo.fnTally(1,@MaxN);

 8. There is no performance penalty for sorting "N" in ascending order because the output is explicity sorted by
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL))

 Revision History:
 Rev 00 - Unknown     - Jeff Moden 
        - Initial creation with error handling for @MaxN.
 Rev 01 - 09 Feb 2013 - Jeff Moden 
        - Modified to start at 0 or 1.
 Rev 02 - 16 May 2013 - Jeff Moden 
        - Removed error handling for @MaxN because of exceptional cases.
 Rev 03 - 22 Apr 2015 - Jeff Moden
        - Modify to handle 1 Trillion rows for experimental purposes.
**********************************************************************************************************************/
        (@ZeroOrOne BIT, @MaxN BIGINT)
RETURNS TABLE WITH SCHEMABINDING AS 
 RETURN WITH
  E1(N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1)                                  --10E1 or 10 rows
, E4(N) AS (SELECT 1 FROM E1 a, E1 b, E1 c, E1 d)      --10E4 or 10 Thousand rows
,E12(N) AS (SELECT 1 FROM E4 a, E4 b, E4 c)            --10E12 or 1 Trillion rows                 
            SELECT N = 0 WHERE ISNULL(@ZeroOrOne,0)= 0 --Conditionally start at 0.
             UNION ALL 
            SELECT TOP(@MaxN) N = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E12 -- Values from 1 to @MaxN
;
GO

До речі ... зауважте, що було створено мільйон і один ряд Tally Table та додано до нього індекс кластеризації приблизно через секунду. Спробуйте ТО з rCTE і подивіться, скільки часу це займе! ;-)

БУДІВЛЯЄТЬСЯ ДЕЯКІ ДАНІ ЗНО

Нам також потрібні деякі дані тесту. Так, я погоджуюся, що всі функції, які ми будемо перевіряти, включаючи rCTE, виконуються в мілісекунді або менше всього за 12 рядків, але це пастка, в яку потрапляє багато людей. Ми пізніше поговоримо про цю пастку пізніше, але поки що, ми зможемо імітувати виклик кожної функції 40 000 разів, тобто про те, скільки разів викликають певні функції в моєму магазині за 8 годин. Уявіть собі, скільки разів подібні функції можуть викликатися у великому інтернет-магазині роздрібної торгівлі.

Отже, ось код для створення 40 000 рядків із випадковими датами, кожен з яких має номер рядка лише для цілей відстеження. Я не витрачав часу на те, щоб скласти час цілими годинами, бо тут це не має значення.

--===== Do this in a nice, safe place that everyone has
    USE tempdb
;
--===== Create/Recreate a Test Date table
     IF OBJECT_ID('dbo.TestDate','U') IS NOT NULL
        DROP TABLE dbo.TestDate
;
DECLARE  @StartDate DATETIME
        ,@EndDate   DATETIME
        ,@Rows      INT
;
 SELECT  @StartDate = '2010' --Inclusive
        ,@EndDate   = '2020' --Exclusive
        ,@Rows      = 40000  --Enough to simulate an 8 hour day where I work
;
 SELECT  RowNum       = IDENTITY(INT,1,1)
        ,SomeDateTime = RAND(CHECKSUM(NEWID()))*DATEDIFF(dd,@StartDate,@EndDate)+@StartDate
   INTO dbo.TestDate
   FROM dbo.fnTally(1,@Rows)
;

ПОБУДУЙТЕ НЕЩЕ ФУНКЦІЇ, ЩО РОБИТИ 12 РАДОВИХ ГОДИН

Далі я перетворив код rCTE у функцію та створив 3 інші функції. Всі вони були створені як високопродуктивні iTVFs (функції вбудованої таблиці). Ви завжди можете сказати, тому що iTVF ніколи не має BEGIN в них, як скалярні або mTVF (багатоточні таблиці з оцінними функціями).

Ось код для побудови цих 4 функцій ... Я назвав їх за методом, який вони використовують, а не тим, що вони роблять просто, щоб полегшити їх ідентифікацію.

--=====  CREATE THE iTVFs
--===== Do this in a nice, safe place that everyone has
    USE tempdb
;
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.OriginalrCTE','IF') IS NOT NULL
        DROP FUNCTION dbo.OriginalrCTE
;
GO
 CREATE FUNCTION dbo.OriginalrCTE
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
WITH Dates AS
(
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,@Date)) [Hour], 
      DATEADD(HOUR,-1,@Date) [Date], 1 Num
    UNION ALL
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,[Date])), 
      DATEADD(HOUR,-1,[Date]), Num+1
    FROM Dates
    WHERE Num <= 11
)
SELECT [Hour], [Date]
FROM Dates
GO
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.MicroTally','IF') IS NOT NULL
        DROP FUNCTION dbo.MicroTally
;
GO
 CREATE FUNCTION dbo.MicroTally
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
 SELECT  [Hour] = DATEPART(HOUR,DATEADD(HOUR,t.N,@Date))
        ,[DATE] = DATEADD(HOUR,t.N,@Date)
   FROM (VALUES (-1),(-2),(-3),(-4),(-5),(-6),(-7),(-8),(-9),(-10),(-11),(-12))t(N)
;
GO
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.PhysicalTally','IF') IS NOT NULL
        DROP FUNCTION dbo.PhysicalTally
;
GO
 CREATE FUNCTION dbo.PhysicalTally
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
 SELECT  [Hour] = DATEPART(HOUR,DATEADD(HOUR,-t.N,@Date))
        ,[DATE] = DATEADD(HOUR,-t.N,@Date)
   FROM dbo.Tally t
  WHERE N BETWEEN 1 AND 12
;
GO
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.TallyFunction','IF') IS NOT NULL
        DROP FUNCTION dbo.TallyFunction
;
GO
 CREATE FUNCTION dbo.TallyFunction
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
 SELECT  [Hour] = DATEPART(HOUR,DATEADD(HOUR,-t.N,@Date))
        ,[DATE] = DATEADD(HOUR,-t.N,@Date)
   FROM dbo.fnTally(1,12) t
;
GO

СТВУЙТЕ ТЕСТУВАННЯ ТЕСТУ, ЩО ВИБУТИТЕ ФУНКЦІЇ

І останнє, але не менш важливе, нам потрібен тестовий джгут. Я роблю перевірку базової лінії, а потім перевіряю кожну функцію однаково.

Ось код для тестового джгута ...

PRINT '--========== Baseline Select =================================';
DECLARE @Hour INT, @Date DATETIME
;
    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = RowNum
        ,@Date = SomeDateTime
   FROM dbo.TestDate
  CROSS APPLY dbo.fnTally(1,12);
    SET STATISTICS TIME,IO OFF;
GO
PRINT '--========== Orginal Recursive CTE ===========================';
DECLARE @Hour INT, @Date DATETIME
;

    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.OriginalrCTE(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO
PRINT '--========== Dedicated Micro-Tally Table =====================';
DECLARE @Hour INT, @Date DATETIME
;

    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.MicroTally(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO
PRINT'--========== Physical Tally Table =============================';
DECLARE @Hour INT, @Date DATETIME
;
    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.PhysicalTally(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO
PRINT'--========== Tally Function ===================================';
DECLARE @Hour INT, @Date DATETIME
;
    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.TallyFunction(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO

Одне, що слід помітити в тестовому джгуті вище, - це те, що я перемикаю весь вихід у "змінні" змінні. Це намагається зберегти вимірювання продуктивності максимально чистими, без будь-яких результатів перекосів на диску чи екрані.

СЛОВО ОБЕРЕЖНО ПРО СТАТИСТИКУ СТАТИСТИКИ

Крім того, слово обережності для потенційних тестувальників ... НЕ МОЖЕТЕ використовувати SET STATISTICS під час тестування функцій Scalar або mTVF. Його можна безпечно використовувати лише у функціях iTVF, як у цьому тесті. Установлено, що SET STATISTICS змушує функції SCALAR працювати в сотні разів повільніше, ніж без них. Так, я намагаюся нахилити ще одну вітряну млину, але це було б ціле повідомлення про довжину статті, і я не маю часу на це. У мене є стаття на SQLServerCentral.com, яка розповідає про все це, але немає сенсу розміщувати посилання тут, тому що хтось згадає про це.

РЕЗУЛЬТАТИ ТЕСТУВАННЯ

Отже, ось результати тесту, коли я запускаю тестовий джгут на своєму маленькому ноутбуці i5 з 6 Гб оперативної пам’яті.

--========== Baseline Select =================================
Table 'Worktable'. Scan count 1, logical reads 82309, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 206 ms.
--========== Orginal Recursive CTE ===========================
Table 'Worktable'. Scan count 40001, logical reads 2960000, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 4258 ms,  elapsed time = 4415 ms.
--========== Dedicated Micro-Tally Table =====================
Table 'Worktable'. Scan count 1, logical reads 81989, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 234 ms,  elapsed time = 235 ms.
--========== Physical Tally Table =============================
Table 'Worktable'. Scan count 1, logical reads 81989, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Tally'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 250 ms,  elapsed time = 252 ms.
--========== Tally Function ===================================
Table 'Worktable'. Scan count 1, logical reads 81989, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 250 ms,  elapsed time = 253 ms.

"BASELINE SELECT", який вибирає дані (кожен рядок створений 12 разів, щоб імітувати той самий обсяг повернення), потрапив близько 1/5 секунди. Все інше вийшло приблизно через чверть секунди. Ну, все, крім цієї кривавої функції rCTE. Це зайняло 4 та 1/4 секунди або 16 разів довше (на 1600% повільніше).

І подивіться на логічні зчитування (IO пам'яті) ... rCTE спожив цілих 2,960 000 (майже 3 мільйони читань), тоді як інші функції споживали лише 82 100. Це означає, що rCTE споживає в 34,3 рази більше IO пам'яті, ніж будь-яка з інших функцій.

ЗАКРИТИ МИСЛИ

Давайте підведемо підсумки. Метод rCTE для виконання цієї "невеликої" 12-рядкової речі використовував на 16 ЧАСІВ (на 1600%) більше процесора (та тривалості) та на 34,3 ЧАС (3,430%) більше IO пам'яті, ніж будь-яка з інших функцій.

Хе ... я знаю, що ти думаєш. "Велика пропозиція! Це лише одна функція."

Так, погодився, але скільки інших функцій у вас є? Скільки інших місць поза функціями у вас є? А у вас є хтось із тих, хто працює з більш ніж 12 рядками кожного пробігу? І чи є ймовірність, що хтось, хто поспішає за методом, може скопіювати код rCTE для чогось набагато більшого?

Гаразд, час тупий. Люди абсолютно не мають сенсу виправдовувати код, який оскаржує продуктивність, лише через передбачуване обмеження кількості рядків або використання. За винятком випадків, коли ви купуєте MPP-коробку на мільйони доларів (не кажучи вже про витрати на перезапис коду, щоб він працював на такій машині), ви не можете придбати машину, яка працює з вашим кодом в 16 разів швидше (виграно SSD і не робити це ... все це було у пам'яті високої швидкості, коли ми його тестували). Продуктивність у коді. Хороші показники в хорошому коді.

Чи можете ви уявити, якби весь ваш код працював "просто" в 16 разів швидше?

Ніколи не обґрунтовуйте поганий чи непростий дію код за низькою кількістю рядків або навіть низьким рівнем використання. Якщо це зробити, вам, можливо, доведеться запозичити одну з вітряків, в яких мене звинувачували, щоб зберегти ваші процесори та диски досить прохолодними. ;-)

СЛОВО НА СЛОВО "СЛОВО"

Так ... я згоден. Семантично кажучи, Таблиця Tally містить цифри, а не "талі". У моїй оригінальній статті на цю тему (це була не оригінальна стаття про техніку, але вона була моєю першою), я назвав її "Tally" не тому, що вона містить, а тому, що вона робить ... це використовується для "підрахунку" замість циклу і для "Tally" щось означає "порахувати" щось. ;-) Назвіть це, що ви будете ... Таблиця чисел, таблиця підрахунків, таблиця послідовностей, що завгодно. Мені все одно. Для мене "Tally" є більш повним значенням і, будучи добрим лінивим DBA, містить лише 5 літер (2 однакові) замість 7, і це простіше сказати для більшості людей. Це також "однина", яка слідує моїй умові іменування таблиць. ;-) Це ' s також те, що стаття, що містила сторінку з книги 60-х років, називала її. Я завжди буду називати це "Табличним столом", і ви все одно будете знати, що я або хтось інший означає. Я також уникаю угорських позначень, як чума, але називав функцію "fnTally", щоб я міг сказати "Ну, якби ви використовували функцію eff-en Tally, яку я вам показав, у вас не було б проблеми з продуктивністю", без того, щоб вона фактично була Порушення HR. ;-) без насправді це порушення HR. ;-) без насправді це порушення HR. ;-)

Мене більше турбують люди, які вчаться правильно користуватися нею, а не вдаватися до таких речей, як rCTE з викликом продуктивності та інші форми прихованого RBAR.


2

Вам потрібно буде отримати RIGHT JOINсвої дані із запитом, що повертає один запис за кожну годину, що вам потрібно.

Дивіться це для кількох способів отримати числа рядків, які ви могли б потім відняти як години від поточного часу.

В Oracle ієрархічний запит на подвійний буде генерувати рядки:

SELECT to_char(sysdate-level/24,'HH24') FROM dual CONNECT BY Level <=24;

Саме з "запитом, що повертає один запис на кожну годину", у мене виникають проблеми. Просто намагаюся з’ясувати спосіб генерації 12 (або 24) записів за кожну годину останніх 12 (або 24) годин.
datagod
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.