简体   繁体   中英

SQL Server 2008 - Converting decimal(4,0) to datetime

I spent the last 40mins looking on here and other websites for an answer. Background to the problem: my ERP system records a date and time when a labour booking is made. It records the booking date as datetime and the booking time as decimal(4) . I'm trying to convert the time (decimal to datetime) so the date and time are one value.

Sample data:

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

There can be multiple bookings in a day for the same operation. My ultimate aim is to find the earliest booking and latest booking for a operation on a job number.

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

You can do this with row_number() and conditional aggregation:

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;

As a note: the title of your question seems to have nothing to do with what you want to accomplish.

You conversion from decimal(4, 0) to time is:

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

Which is just adding your total minutes to 00:00 to get a time, where your total minutes is calculated as (hours * 60) + minutes where

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

HOWEVER if it is not too late you should scrap this approach completely.

In SQL Server there is rarely a need to store date and time columns separately, the best approach is to have a single DATETIME2 column, and if for any reason you need separate columns (such as indexing) use computed columns eg

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

If you must have the two columns stored separately at the very least you should use the TIME data type to store time, not DECIMAL(4, 0) . The best approach to your situation is to fix the actual problem, which is incorrect data types, rather than the question you have asked. If you were to do this you would have data like:

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

etc.

Then your query is as simple as

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

The code to do this correction would be:

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];

If you already have lots of existing code that uses these columns, you could use a computed column to do the calculation for you:

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

eg

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;

As the above implies, I'd recommend just returning the date and time as a single column, but if you do want them as separate columns, then you should at least use the TIME type:

Either way I would recommend returning a full date time, or at the very least using date and time columns, eg

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;

If you can't make any schema changes you can just include the formula in your actual query (after you have been to punch your dba for using decimal to store time):

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM