2015-01-28 6 views
0

Я провел последние 40 минут, глядя на здесь и на другие сайты для ответа. Предыстория проблемы: моя система ERP записывает дату и время, когда производится бронирование труда. Он записывает дату бронирования как дату и время бронирования, как decimal(4). Я пытаюсь преобразовать время (десятичное в datetime), так что дата и время являются одним значением.SQL Server 2008 - Преобразование десятичных чисел (4,0) в datetime

Образец данных:

Job Op Date   Time 
---------------------------------- 
1 10 06/01/2015 254 
1 20 06/01/2015 254 
1 20 06/01/2015 542 
1 20 06/01/2015 1347 
1 20 07/01/2015 1340 
1 30 07/01/2015 1408 
1 30 07/01/2015 1340 
1 30 08/01/2015 1037 
1 40 06/01/2015 543 
1 40 06/01/2015 1348 
1 40 08/01/2015 1038 
1 50 07/01/2015 1219 
1 50 08/01/2015 1039 
1 60 07/01/2015 1220 
1 60 10/01/2015 1054 
1 60 12/01/2015 859 

Там может быть несколько заказов в день в течение одной операции. Моя конечная цель - найти раннее бронирование и последний заказ на операцию на номер вакансии.

Job Op Start  End   StartTime FinishTime 
------------------------------------------------------------- 
1 10 06/01/2015 06/01/2015  254  254 
1 20 06/01/2015 07/01/2015  254  1340 
1 30 07/01/2015 08/01/2015  1340  1037 
1 40 06/01/2015 08/01/2015  543  1038 
1 50 07/01/2015 08/01/2015  1219  1039 
1 60 07/01/2015 12/01/2015  1220  859 
+0

Что вы используете? Пожалуйста, отметьте вопрос соответствующим образом. –

ответ

0

Вы можете сделать это с row_number() и условной агрегацией:

select s.job, s.op, 
     max(case when seqnum = 1 then date end) as start, 
     max(case when seqnum = cnt then date end) as end, 
     max(case when seqnum = 1 then time end) as start_time, 
     max(case when seqnum = cnt then time end) as end_time 
from (select s.*, 
      row_number() over (partition by job, op order by date, time) as seqnum, 
      count(*) over (partition by job, op) as cnt 
     from sample s 
    ) s 
group by job, op; 

Как примечание: название вашего вопроса, кажется, не имеет ничего общего с тем, что вы хотите достичь.

0

Вы преобразование из десятичной системы счисления (4, 0) на время:

DATEADD(MINUTE, (FLOOR([Time]/100) * 60) + ([Time] % 100), '00:00') 

Что только добавляют ваши общие минуты 00:00, чтобы получить время, когда ваши общие минуты рассчитываются как (hours * 60) + minutes где

Hours = FLOOR([Time]/100) 
Minutes = ([Time] % 100) 

ОДНАКО, если это не слишком поздно, вы должны отказаться этот подход полностью.

В SQL Server редко приходится создавать столбцы даты и времени отдельно, лучший подход состоит в том, чтобы иметь один столбец DATETIME2, и если по какой-либо причине вам нужны отдельные столбцы (например, индексирование), используйте вычисленные столбцы, например.

ALTER TABLE T ADD StartDate AS CAST(StartDateTime AS DATE); 

Если вы должны иметь две колонки, хранящиеся отдельно, по крайней мере, вы должны использовать тип TIME данных для хранения времени, не DECIMAL(4, 0). Лучший подход к вашей ситуации - это исправить актуальную проблему, которая является неправильным типом данных, а не вопрос, который вы задали. Если вы должны были сделать это, вы бы данные, такие как:

Job Op JobDateTime 
---------------------------------- 
1 10 06/01/2015 02:54 
1 20 06/01/2015 02:54 
1 20 06/01/2015 05:42 
1 20 06/01/2015 13:47 
1 20 07/01/2015 13:40 
1 30 07/01/2015 14:08 
1 30 07/01/2015 13:40 
1 30 08/01/2015 10:37 
1 40 06/01/2015 05:43 

и т.д.

Тогда ваш запрос так прост, как

SELECT JOb, Op, FirstJob = MIN(JobDateTime), LastJob = MAX(JobDateTime) 
FROM T 
GROUP BY JOb, Op; 

код, чтобы сделать это исправление будет:

ALTER TABLE [YourTable] ADD JobDateTime DATETIME2 NOT NULL; 

UPDATE [YourTable] 
SET  JobDateTime = DATEADD(MINUTE, (FLOOR([Time]/100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME))); 

ALTER TABLE [YourTable] DROP COLUMN [Date]; 
ALTER TABLE [YourTable] DROP COLUMN [Time]; 

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

ALTER TABLE YourTable 
ADD JobDateTime AS DATEADD(MINUTE, (FLOOR([Time]/100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME)); 

e.g.

CREATE TABLE #T (Job INT, Op INT, [Date] DATE, [Time] DECIMAL(4, 0)); 
INSERT #T (Job, Op, [Date], [Time]) 
VALUES 
    (1, 10, '2015-06-01', 254), 
    (1, 20, '2015-06-01', 254), 
    (1, 20, '2015-06-01', 542), 
    (1, 20, '2015-06-01', 1347), 
    (1, 20, '2015-07-01', 1340), 
    (1, 30, '2015-07-01', 1408), 
    (1, 30, '2015-07-01', 1340), 
    (1, 30, '2015-08-01', 1037), 
    (1, 40, '2015-06-01', 543), 
    (1, 40, '2015-06-01', 1348), 
    (1, 40, '2015-08-01', 1038), 
    (1, 50, '2015-07-01', 1219), 
    (1, 50, '2015-08-01', 1039), 
    (1, 60, '2015-07-01', 1220), 
    (1, 60, '2015-10-01', 1054), 
    (1, 60, '2015-12-01', 859); 

ALTER TABLE #T 
ADD JobDateTime AS DATEADD(MINUTE, (FLOOR([Time]/100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME)); 

SELECT Job, 
     Op, 
     FirstJob = MIN(JobDateTime), 
     LastJob = MAX(JobDateTime) 
FROM #T 
GROUP BY Job, Op; 

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

В любом случае я бы рекомендовал вернуть полное время или, по крайней мере, использовать столбцы даты и времени, например

SELECT Job, 
     Op, 
     [Start] = CAST(MIN(JobDateTime) AS DATE), 
     [End] = CAST(MAX(JobDateTime) AS DATE), 
     StartTime = CAST(MIN(JobDateTime) AS TIME), 
     EndTime = CAST(MAX(JobDateTime) AS TIME) 
FROM #T 
GROUP BY Job, Op; 

Если вы не можете делать какие-либо изменения схемы вы можете просто включать формулу в Вашем запросе (после того, как вы были пробивать свой дБА для использования десятичной для хранения времени):

SELECT Job, 
     Op, 
     FirstJob = MIN(DATEADD(MINUTE, (FLOOR([Time]/100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME))), 
     LastJob = MAX(DATEADD(MINUTE, (FLOOR([Time]/100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME))) 
FROM #T 
GROUP BY Job, Op; 
Смежные вопросы