2012-01-19 33 views
6

Tôi đang cố chạy một số báo cáo và phải giải quyết toàn bộ vấn đề về giờ lao động của nhân viên qua nửa đêm. Nó xảy ra với tôi mặc dù rằng tôi có thể chia các hồ sơ mà qua nửa đêm thành hai hồ sơ như thể nhân viên đã hết giờ vào nửa đêm và đồng thời quay trở lại vào lúc nửa đêm do đó tránh được vấn đề nửa đêm hoàn toàn.Ghi lại các bản ghi thời gian qua nửa đêm

Vì vậy, nếu tôi có:

EmployeeId InTime      OutTime 
---   ----------------------- ----------------------- 
1   2012-01-18 19:50:04.437 2012-01-19 03:30:02.433 

chị điều gì sẽ là cách thanh lịch nhất để tách hồ sơ này như sau:

EmployeeId InTime      OutTime 
---   ----------------------- ----------------------- 
1   2012-01-18 19:50:04.437 2012-01-19 00:00:00.000 
1   2012-01-19 00:00:00.000 2012-01-19 03:30:02.433 

Và vâng, tôi đã nghĩ kỹ lưỡng thông qua ảnh hưởng gì điều này có thể có về chức năng hiện có ... đó là lý do tại sao tôi chọn làm điều này trong một bảng tạm thời sẽ không ảnh hưởng đến chức năng hiện có.

+1

Xem http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=42516&bcsi_scan_0070CC03028EB70D=JJykjVHNGapjNgIKjEMdLQkAAADDDLIH&bcsi_scan_filename=topic.asp không giống chính xác. Hơn cả giải pháp dựa trên SQL 2k của nó. Nhưng tôi hy vọng nó có thể cung cấp cho bạn một số gợi ý. – vmvadivel

+0

Vì vậy, nửa đêm qua của nó ... vấn đề là gì ... tổng số giờ làm việc trong một ca nhất định? hoặc nếu nó vượt qua cả hai ngày, mà ngày nó sẽ hiển thị trong? – DRapp

+0

@DRapp Đối với mục đích của báo cáo 'này' (mặc dù không phải tất cả) lao động sẽ xuất hiện vào ngày nó thực sự thuộc về ... không nhất thiết là ngày khi nhân viên bắt đầu ca làm việc của họ. Vì vậy, đó là lý do tại sao tôi nghĩ rằng đây là giải pháp tốt nhất để thực hiện điều đó theo cách mà dữ liệu có ý nghĩa nhất để làm việc. –

Trả lời

6

này có thể giúp:

DECLARE @tbl TABLE 
    (
     EmployeeId INT, 
     InTime DATETIME, 
     OutTime DATETIME 
    ) 

INSERT INTO @tbl(EmployeeId,InTime,OutTime) VALUES (1,'2012-01-18 19:50:04.437','2012-01-19 03:30:02.433') 
INSERT INTO @tbl(EmployeeId,InTime,OutTime) VALUES (2,'2012-01-18 19:50:04.437','2012-01-18 20:30:02.433') 
INSERT INTO @tbl(EmployeeID,InTime,OutTime) VALUES (3,'2012-01-18 16:15:00.000','2012-01-19 00:00:00.000') 
INSERT INTO @tbl(EmployeeID,InTime,OutTime) VALUES (4,'2012-01-18 00:00:00.000','2012-01-18 08:15:00.000') 
SELECT 
    tbl.EmployeeId, 
    tbl.InTime, 
    DATEADD(dd, DATEDIFF(dd, 0, tbl.OutTime), 0) AS OutTime 
FROM 
    @tbl AS tbl 
WHERE 
    DATEDIFF(dd,tbl.InTime,tbl.OutTime)=1 
UNION ALL 
SELECT 
    tbl.EmployeeId, 
    CASE WHEN DATEDIFF(dd,tbl.InTime,tbl.OutTime)=1 
     THEN DATEADD(dd, DATEDIFF(dd, 0, tbl.OutTime), 0) 
     ELSE tbl.InTime 
    END AS InTime, 
    tbl.OutTime 
FROM @tbl AS tbl 
ORDER BY EmployeeId 
0

Hãy thử điều này, bởi vì bạn có thể thực hiện chèn một lựa chọn và bên trong lựa chọn của bạn, bạn có thể đặt giá trị để sử dụng là các ngày khác nhau.

Đối Thêm hàng mới:

insert into table ("EMPLOYEE_ID","INTIME","OUTTIME") values 
SELECT EMPLOYEE_ID,date(INTIME),OUTTIME 
FROM table 
where date(intime) < date(outtime) 

Cập nhật hàng gốc:

update table 
set outtime =date(outtime) 
where date(intime)= date(outtime) 
1

Nếu cho báo cáo, sau đó bạn chỉ nên có thể thực hiện truy vấn/công đoàn cung cấp hai bản ghi trong các điều kiện đó từ bản gốc bắt đầu ... Nếu không có SQL-Se rver 2008, tôi chỉ có thể cung cấp truy vấn mã giả cho bạn.

Phần đầu tiên nhận tất cả hồ sơ dựa trên bất kỳ điều kiện phạm vi nào của bạn để hiển thị. Giá trị của "OutTime" là có điều kiện ... nếu nó trong cùng một ngày, sau đó không vượt qua, chỉ cần sử dụng thời gian ra. Nếu IS vào ngày tiếp theo, hãy sử dụng tính năng truyền để tự động xây dựng ngày 'YYYY-MM-DD' (sẽ mặc định là 00:00:00) như bạn muốn làm thời gian OUT.

UNION sẽ CHỈ lấy những hồ sơ tương tự đủ điều kiện ở FIRST, nơi các ngày vào/ra là KHÁC BIỆT. Như vậy, chúng tôi BIẾT chúng tôi muốn bất kỳ OutTime nào hoạt động như InTime, nhưng dựa trên thời gian "00:00:00", vì vậy việc tạo cùng một trường ngày/giờ được thực hiện chính xác và cho các bản ghi này, sử dụng giá trị "OutTime" cuối cùng. Cột bổ sung cho "TimeSplit" của '1' hoặc '2' là đảm bảo rằng chúng tôi vẫn có thể nhóm theo ID nhân viên, nhưng từ đó, đảm bảo rằng các mục '1' (bắt đầu thay đổi) là đầu tiên, theo sau bởi bất kỳ người nào tương ứng có mục nhập '2' cho ngày trùng lặp trong ca làm việc của họ.

select 
     tc.EmployeeID, 
     '1' as TimeSplit, 
     tc.InTime, 
     case when datepart(dd, tc.InTime) = datepart(dd, tc.OutTime) 
     then tc.OutTime 
     else CAST(CAST(datepart(yyyy, tc.OutTime) AS varchar) 
       +'-'+ CAST(datepart(mm, tc.OutTime) AS varchar) 
       +'-'+ CAST(datepart(dd, tc.OutTime) AS varchar) AS DATETIME) 
     end as OutTime 
    from 
     TimeCard tc 
    where 
     YourDateRangeConditions... 
    ORDER BY 
     tc.EmployeeID, 
     TimeSplit 
UNION ALL 
select 
     tc.EmployeeID, 
     '2' as TimeSplit, 
     CAST( CAST(datepart(yyyy, tc.OutTime) AS varchar) 
     +'-'+ CAST(datepart(mm, tc.OutTime) AS varchar) 
     +'-'+ CAST(datepart(dd, tc.OutTime) AS varchar) AS DATETIME) 
     end as InTime 
     tc.OutTime 
    from 
     TimeCard tc 
    where 
     YourDateRangeConditions... 
     AND NOT datepart(dd, tc.InTime) = datepart(dd, tc.OutTime) 
2

Giải pháp sau đây sử dụng bảng số (dưới dạng tập hợp con của bảng hệ thống master..spt_values) để chia phạm vi thời gian. Nó có thể phân chia phạm vi trải rộng một số ngày tùy ý (tối đa 2048 với spt_values, nhưng với bảng số riêng của bạn, bạn có thể đặt mức tối đa khác). Các trường hợp cụ thể của dãy kéo dài 1- 2 ngày không được đề cập ở đây, nhưng tôi tin rằng phương pháp này là đủ nhẹ để bạn có thể thử:

; 
WITH LaborHours (EmployeeId, InTime, OutTime) AS (
    SELECT 
    1, 
    CAST('2012-01-18 19:50:04.437' AS datetime), 
    CAST('2012-01-18 03:30:02.433' AS datetime) 
), 
HoursSplit AS (
    SELECT 
    h.*, 
    SubInTime = DATEADD(DAY, DATEDIFF(DAY, 0, h.InTime) + v.number + 0, 0), 
    SubOutTime = DATEADD(DAY, DATEDIFF(DAY, 0, h.InTime) + v.number + 1, 0) 
    FROM LaborHours h 
    INNER JOIN master..spt_values v 
     ON number BETWEEN 0 AND DATEDIFF(DAY, h.InTime, h.OutTime) 
    WHERE v.type = 'P' 
), 
HoursSubstituted AS (
    SELECT 
    EmployeeId, 
    InTime = CASE WHEN InTime > SubInTime THEN InTime ELSE SubInTime END, 
    OutTime = CASE WHEN OutTime < SubOutTime THEN OutTime ELSE SubOutTime END 
    FROM HoursSplit 
) 
SELECT * 
FROM HoursSubstituted 

Về cơ bản, đó là một phương pháp hai bước.Trước tiên, chúng tôi sử dụng bảng số để nhân bản mỗi hàng nhiều lần với số ngày phạm vi kéo dài và chuẩn bị các dải phụ ‘chuẩn’ bắt đầu từ nửa đêm và kết thúc vào nửa đêm tiếp theo.

Tiếp theo, chúng tôi so sánh sự bắt đầu của một phạm vi phụ với phần đầu của dải ô để xem đây có phải là phạm vi phụ đầu tiên hay không, trong trường hợp này chúng tôi sử dụng InTime làm khởi đầu. Tương tự, chúng tôi so sánh các kết thúc để xem liệu chúng tôi có nên sử dụng OutTime hoặc chỉ nửa đêm khi kết thúc của khoảng con đó.

Các vấn đề liên quan