Справка по SQL-запросам - PullRequest
0 голосов
/ 02 июня 2009

Я использую SQL SERVER - 2000

Структура таблицы

CARDEVENTDATE       CARDEVENTTIME   CARDNO
20090224            92007           485
20090224            92345           321
20090225            163932          168
20090225            164630          471
20090225            165027          488
20090225            165137          247
20090225            165147          519
20090225            165715          518
20090225            165749          331
20090303            162059          240
20090303            162723          518
20090303            155029          386
20090303            155707          441
20090303    162824  331

Cardeventdate и Cardeventtime - тип данных nvarchar Дата и время - это отдельный столбец

Я хочу получить данные между

Вчера 03:00:01 до сегодняшнего дня 03:00:00 AM Позавчера до 03:00:01 до вчерашнего 03:00:00 Так далее …… ..

Я попробовал приведенный ниже запрос

Select Cardno, cardeventdate, min(cardeventtime), max(cardeventtime) 
from table 
where cardeventtime between 030001 to 030000

Select Cardno, Cardeventdate, Min(cardeventtime), max(cardeventtime) 
from table 
where Cardeventtime >030001 and  Cardeventtime < 030000

Ничего не отображается в результате, потому что оно занимает сегодняшнее время с 03.00 до 03.01.

Select Cardno, Cardeventdate, min (cardeventtime), max (cardeventtime) 
from table 
where cardeventtime < 030000 and cardeventtime > previous day time – query help 

Точно мне нужно вчера с 03.00.01 до сегодняшнего дня 03.00.00 утра, данные за день до вчерашнего дня с 03.00.01 до вчерашнего дня 03.00.00 утра данные …………………. Итак, на

Мне нужен запрос sql для вышеуказанного условия. Кто-нибудь может мне помочь?

(редактировать: мне нужна дата со вчерашнего утра до сегодняшнего утра, до 03:00)

Ответы [ 7 ]

1 голос
/ 02 июня 2009

Ниже приведен тест на SQL Server 2005 Express. Если SQL Server 2000 не имеет общих табличных выражений (CTE), вместо этого можно использовать представление для создания того же, что и cteTbl. И я надеюсь, что SQL Server 2000 поддерживает CASE-WHEN-END.

Идея, которую я использую в этом, заключается в том, чтобы увеличить количество часов в день с 24 до 27 часов (+3), но только в том случае, если [CardEventTime] меньше или равно 03:00:00 (24 часа). Я добавляю 24 часа. и [CardEventDate] вычесть 1d.

CREATE TABLE tbl (
  CardEventDate INTEGER
  ,CardEventTime INTEGER
  ,CardNo INTEGER
)

INSERT INTO tbl VALUES (20090224,92007,485)
INSERT INTO tbl VALUES (20090224,92345,321)
INSERT INTO tbl VALUES (20090225,163932,168)
INSERT INTO tbl VALUES (20090225,164630,471)
INSERT INTO tbl VALUES (20090225,165027,488)
INSERT INTO tbl VALUES (20090225,165137,247)
INSERT INTO tbl VALUES (20090225,165147,519)
INSERT INTO tbl VALUES (20090225,165715,518)
INSERT INTO tbl VALUES (20090225,165749,331)
INSERT INTO tbl VALUES (20090303,162059,240)
INSERT INTO tbl VALUES (20090303,162723,518)
INSERT INTO tbl VALUES (20090303,155029,386)
INSERT INTO tbl VALUES (20090303,155707,441)
INSERT INTO tbl VALUES (20090303,162824,331)

-- Some boundary test values, for only one cardno.
INSERT INTO tbl VALUES (20090330,235959,331)
INSERT INTO tbl VALUES (20090331,000000,331)
INSERT INTO tbl VALUES (20090331,025959,331)
INSERT INTO tbl VALUES (20090331,030000,331)
INSERT INTO tbl VALUES (20090331,030001,331)
INSERT INTO tbl VALUES (20090331,235959,331)
INSERT INTO tbl VALUES (20090401,000000,331)
INSERT INTO tbl VALUES (20090401,025959,331)
INSERT INTO tbl VALUES (20090401,030000,331)
INSERT INTO tbl VALUES (20090401,030001,331)
go

WITH 
cteTbl AS (
  SELECT
    CardEventDate,
    CardEventTime,
    CardNo,
    CASE 
      WHEN CardEventTime <= 30000 THEN dateadd(dd, -1, cast(CardEventDate AS VARCHAR))
      WHEN CardEventTime > 30000 THEN cast(cast(CardEventDate AS VARCHAR) AS DATETIME)
    END AS ShiftedCardEventDate,
    CASE 
      WHEN CardEventTime <= 30000 THEN CardEventTime+240000
      WHEN CardEventTime > 30000 THEN CardEventTime
    END AS ShiftedCardEventTime
  FROM tbl
)
SELECT
  CardNo, 
  ShiftedCardEventDate,
  --min(shiftedCardEventTime) as [MinCardEventTime], 
  --max(shiftedCardEventTime) as [MaxCardEventTime],
  right('000000'+cast((min(shiftedCardEventTime) % 240000) AS VARCHAR), 6) AS [NormalizedMinTime],  
  right('000000'+cast((max(shiftedCardEventTime) % 240000) AS VARCHAR), 6) AS [NormalizedMaxTime]
FROM cteTbl
GROUP BY 
  CardNo, 
  ShiftedCardEventDate
0 голосов
/ 03 июня 2009

Решение с использованием только запроса:

SELECT  CardEventDate, CardEventTime, CardNo
        ,(1000000*CAST(CardEventDate AS BIGINT) + CAST(CardEventTime AS BIGINT)) AS CardEventDateTimeINT
        ,((1000000*CAST(CardEventDate AS BIGINT) + CAST(CardEventTime AS BIGINT))-150000)/1000000 AS StartDate
FROM    "table"
WHERE   ((1000000*CAST(CardEventDate AS BIGINT) + CAST(CardEventTime AS BIGINT))-150000)/1000000 = '20090223'

Параметры:

  • '20090223' - дата начала вашего 24-часового периода (ваш фильтр)
  • 150000 в предложении WHERE представляет время начала 15:00:00. Изменение его даст вам различные 24-часовые диапазоны. Вы можете хотеть, чтобы это было 150001, если точное время должно перейти к другой дате.
    • Удаление фильтра (предложение WHERE) даст вам все результаты, которые вы можете отфильтровать позже, если вы раскомментируете столбец «StartDate»

Способ, которым это реализовано, состоит в составлении DATETIME из вашей даты и времени, но с использованием не типа данных DATETIME, а просто BIGINT, так что значением 20090224092007 будет дата 20090224 и время 092007. Самое важное в том, что он все еще можно сортировать, и его легко отрезать / сдвигать, просто используя раздел INTEGER. Это то, что я покупаю, вычитая 150000 (время 15:00:00).

Результат (с фильтром, как в запросе выше):

CardEventDate CardEventTime CardNo CardEventDateTimeINT StartDate
------------- ------------- ------ -------------------- --------------------
20090224      92007         485    20090224092007       20090223
20090224      92345         321    20090224092345       20090223

Ниже показан результат без какого-либо фильтра, так что вы можете отфильтровать по StartDate позже:

CardEventDate CardEventTime CardNo CardEventDateTimeINT StartDate
------------- ------------- ------ -------------------- --------------------
20090224      92007         485    20090224092007       20090223
20090224      92345         321    20090224092345       20090223
20090225      163932        168    20090225163932       20090225
20090225      164630        471    20090225164630       20090225
20090225      165027        488    20090225165027       20090225
20090225      165137        247    20090225165137       20090225
20090225      165147        519    20090225165147       20090225
20090225      165715        518    20090225165715       20090225
20090225      165749        331    20090225165749       20090225
20090303      162059        240    20090303162059       20090303
20090303      162723        518    20090303162723       20090303
20090303      155029        386    20090303155029       20090303
20090303      155707        441    20090303155707       20090303
20090303      162824        331    20090303162824       20090303

Это версия с GROUP BY, MIN (..) и MAX (..):

SELECT  CardNo, 
        ((1000000*CAST(CardEventDate AS BIGINT) + CAST(CardEventTime AS BIGINT))-30000)/1000000 AS CardEvenDateAdjusted, 
        MIN(CardEventTime) AS MinTime, 
        MAX(CardEventTime) AS MaxTime
        --,COUNT(*) AS NUM
FROM    "table"
GROUP BY CardNo, ((1000000*CAST(CardEventDate AS BIGINT) + CAST(CardEventTime AS BIGINT))-30000)/1000000

Обратите внимание на несколько вещей:

  • CardEvenDateAdjusted не совсем подходит для тех, кто находится между 00:00:00 и 03:00:00 следующего дня
  • MinTime, который меньше, чем 030000, будет означать, что это фактически следующий день, так что на самом деле это не действительно MIN ...
  • Если ваш CardEventTime является строковым (не целочисленным), то вы должны убедиться, что он имеет начальные нули (020000, а не 20000), в противном случае MIN, MAX не будет правильно сортировать его, так что 20000 выше 150000.

Опять же: если вы не зададите ХОРОШИЙ вопрос, вы НЕ получите ответ, который ищете.

0 голосов
/ 02 июня 2009

Шаг 1

Сначала поместите оба столбца с датой и временем в один столбец (т. Е. carddate) типа datetime.

Шаг 2
Если вы хотите сделать группировку на основе некоторого времени разделения в течение дня, сделайте что-то вроде этого (время разделения в примере 3 часа ночи):

select min(carddate) as Minimum, max(carddate) as Maximum
from sampleTable
group by
    year(dateadd(hour, -3, carddate)),
    month(dateadd(hour, -3, carddate)),
    day(dateadd(hour, -3, carddate))

Но вы не сможете получить номера карт в группах так просто, как это. Вам придется использовать пользовательские функции для такого рода функций

0 голосов
/ 02 июня 2009

Сценарий SQLServer2005, но с использованием таблиц #Temp вы сможете преобразовать его в пригодный для использования сценарий SQLServer2000.

Если я вас правильно понимаю, следующий скрипт группирует записи по dd 03: 00: 00 - dd + 1 03: 00: 00

DECLARE @Table TABLE (
  CARDEVENTDATE INTEGER
  , CARDEVENTTIME INTEGER
  , CARDNO INTEGER)

DECLARE @TableDateTime TABLE (
  CARDEVENTDATETIME DATETIME
)

INSERT INTO @Table VALUES (20090224,92007,485)
INSERT INTO @Table VALUES (20090224,92345,321)
INSERT INTO @Table VALUES (20090225,163932,168)
INSERT INTO @Table VALUES (20090225,164630,471)
INSERT INTO @Table VALUES (20090225,165027,488)
INSERT INTO @Table VALUES (20090225,165137,247)
INSERT INTO @Table VALUES (20090225,165147,519)
INSERT INTO @Table VALUES (20090225,165715,518)
INSERT INTO @Table VALUES (20090225,165749,331)
INSERT INTO @Table VALUES (20090303,162059,240)
INSERT INTO @Table VALUES (20090303,162723,518)
INSERT INTO @Table VALUES (20090303,155029,386)
INSERT INTO @Table VALUES (20090303,155707,441)
INSERT INTO @Table VALUES (20090303,162824,331)

INSERT INTO @TableDateTime
SELECT 
  [DATETIME-3] = 
    DATEADD(MONTH, ((CARDEVENTDATE/10000-1900)*12)+(CARDEVENTDATE/100)%100-1, CARDEVENTDATE%100-1) 
    + DATEADD(SS, (((CARDEVENTTIME/10000)-3)*3600)+(((CARDEVENTTIME/100)%100)*60)+CARDEVENTTIME%100, 0)
FROM @Table

SELECT CAST(CAST(tdt1.CARDEVENTDATETIME-1 AS INTEGER) AS DATETIME), COUNT(*)
FROM @TableDateTime tdt1
GROUP BY CAST(tdt1.CARDEVENTDATETIME-1 AS INTEGER)

/*
  What do all the casts, div's and mods mean
*/
SELECT
  /* Split */
  [YEAR] = CARDEVENTDATE / 10000
  , [MONTH] = (CARDEVENTDATE / 100) % 100
  , [DAY] = CARDEVENTDATE % 100
  , [HOUR] = CARDEVENTTIME / 10000  
  , [MINUTE] = (CARDEVENTTIME / 100) % 100
  , [SECOND] = CARDEVENTTIME % 100  
  /* Date & Time */
  , [DATE] = DATEADD(MONTH, ((CARDEVENTDATE/10000-1900)*12)+(CARDEVENTDATE/100)%100-1, CARDEVENTDATE%100-1)
  , [TIME] = DATEADD(SS, (CARDEVENTTIME/10000*3600)+(((CARDEVENTTIME/100)%100)*60)+CARDEVENTTIME%100, 0)
  /* DateTime */
  , [DATETIME] = 
      DATEADD(MONTH, ((CARDEVENTDATE/10000-1900)*12)+(CARDEVENTDATE/100)%100-1, CARDEVENTDATE%100-1)
      + DATEADD(SS, (CARDEVENTTIME/10000*3600)+(((CARDEVENTTIME/100)%100)*60)+CARDEVENTTIME%100, 0)
  , [DATETIME-3] = 
      DATEADD(MONTH, ((CARDEVENTDATE/10000-1900)*12)+(CARDEVENTDATE/100)%100-1, CARDEVENTDATE%100-1) 
      + DATEADD(SS, (((CARDEVENTTIME/10000)-3)*3600)+(((CARDEVENTTIME/100)%100)*60)+CARDEVENTTIME%100, 0)
FROM @Table
ORDER BY [DATETIME]
0 голосов
/ 02 июня 2009

не могли бы вы просто позвонить:

select *
from someTable
where cardeventtime not between 30000 and 30001
order by cardeventdate, cardeventtime
0 голосов
/ 02 июня 2009

Это было бы неверно, потому что условие всегда будет ложным: (вы сохраняете дату как целое число вместо даты и времени, и целое число не может знать, что оно должно быть в полночь)

Select Cardno, Cardeventdate, Min(cardeventtime), 
  max(cardeventtime) from table where Cardeventtime >030001 
      and Cardeventtime < 030000

Запрос должен быть написан так:

Select Cardno, Cardeventdate, Min(cardeventtime), 
  max(cardeventtime) from table where (Cardeventtime between 030001 and 120000)
      OR (cardeventtime between 000000 and 030000)

Как только вы включите это в другие ваши запросы, вы сможете найти решение.

Редактировать: извините, в запросе вместо И имелось ИЛИ.

0 голосов
/ 02 июня 2009

Форматирование даты в запросе зависит от конкретной реализации.

Right SQLServer2000, Вы хотите, чтобы ваш запрос использовал даты как даты, а не как числа. Вы действительно должны иметь одно поле типа datetime, а не два отдельных поля. Но если у вас нет контроля над этим, то вам нужно сделать некоторое добавление даты и времени. Я приведу пример.

Попробуйте что-то вроде этого:

SELECT * FROM table
WHERE
  (DATEDIFF(dd, GetDate(), CARDEVENTDATE) = 1  AND  CARDEVENTTIME > 030001 )  OR
  (DATEDIFF(dd, GetDate(), CARDEVENTDATE) = 0  AND  CARDEVENTTIME < 030000 )
...