SQL Server:如果条件表中没有天,则选择范围中的每一天

时间:2017-04-05 04:03:23

标签: sql-server stored-procedures

我在SQL Server中有一个表RRHH.ReportAssistence。所有数据都从我的软件自动完成标记,该软件已完成该表。

cod_mark (int auto increment)
cod_personal (int)
cod_schedule (int) 
date_mark (date) 
check_in (time(0)) 
check_out (time(0))

查询:

select * from RRHH.ReportAssistence

cod_mark / cod_personal / cod_schedule / date_mark / check_in / check_out    
--------------------------------------------------------------------------    
1        / 39           /   1          /2017-03-02 / NULL     / 18:10:00    
2        / 39           /   1          /2017-03-05 / NULL     / 18:02:00
3        / 39           /   1          /2017-03-08 / 09:20:00 /  NULL   
4        / 39           /   1          /2017-03-10 / NULL     / 18:04:00
5        / 39           /   1          /2017-03-20 / 08:56:00 / 18:53:00
6        / 39           /   1          /2017-03-21 / 08:52:00 / 18:10:00
7        / 39           /   1          /2017-03-22 / 08:56:00 / 18:09:00
8        / 39           /   1          /2017-03-23 / NULL     / 18:05:00

我需要一个存储过程,列出范围的所有日期并完成所有日期范围,如果不存在任何“date_mark”显示临时列“CONDITION”= LEFT,如果时间在“check_in”到09:15:00显示“CONDITION”= LATE,如果少到09:15:00显示“CONTIDION”= OK,如果没有check_in“CONDITION”= LEFT IN, 如果没有check_out没有问题“CONDITION”= OK

期望的结果:

SP_showMeReportAssistance (cod_personal), (startDate), (endDate)

execute SP_showMeReportAssistance 39, '01/03/2017', '23/03/2017'

cod_personal / cod_schedule / date_mark / check_in / check_out / CONDITION

39           /   1         /2017-03-01 / NULL     / NULL       / LEFT   
39           /   1         /2017-03-02 / NULL     / 18:10:00   / LEFT IN
39           /   1         /2017-03-03 / NULL     / NULL       / LEFT   
39           /   1         /2017-03-04 / NULL     / NULL       / LEFT   
39           /   1         /2017-03-05 / NULL     / 18:02:00   / LEFT IN
39           /   1         /2017-03-06 / NULL     / NULL       / LEFT   
39           /   1         /2017-03-07 / NULL     / NULL       / LEFT   
39           /   1         /2017-03-08 / 09:20:00 / NULL       / LATE
39           /   1         /2017-03-09 / NULL     / NULL       / LEFT   
39           /   1         /2017-03-10 / NULL     / 18:04:00   / LEFT IN
39           /   1         /2017-03-11 / NULL     / NULL       / LEFT
39           /   1         /2017-03-12 / NULL     / NULL       / LEFT
39           /   1         /2017-03-13 / NULL     / NULL       / LEFT
39           /   1         /2017-03-14 / NULL     / NULL       / LEFT
39           /   1         /2017-03-15 / NULL     / NULL       / LEFT
39           /   1         /2017-03-16 / NULL     / NULL       / LEFT
39           /   1         /2017-03-17 / NULL     / NULL       / LEFT
39           /   1         /2017-03-18 / NULL     / NULL       / LEFT
39           /   1         /2017-03-19 / NULL     / NULL       / LEFT
39           /   1         /2017-03-20 / 08:56:00 / 18:53:00   / OK
39           /   1         /2017-03-21 / 08:52:00 / 18:10:00   / OK
39           /   1         /2017-03-22 / 08:56:00 / 18:09:00   / OK
39           /   1         /2017-03-23 / NULL     / 18:05:00   / LEFT IN    

3 个答案:

答案 0 :(得分:1)

您需要先根据传递给过程的日期生成日期列表。并LEFT JOIN到您的实际表格。并通过向CASE提供您的条件来获取您的条件列。

<强>架构:

CREATE TABLE ReportAssistence (
    cod_mark INT IDENTITY
    ,cod_personal INT
    ,cod_schedule INT
    ,date_mark DATE
    ,check_in TIME(0)
    ,check_out TIME(0)
    )


INSERT INTO ReportAssistence

SELECT 39 , 1 ,'2017-03-02' , NULL , '18:10:00'
UNION ALL 
SELECT 39 , 1 ,'2017-03-05' , NULL , '18:02:00'
UNION ALL
SELECT 39 , 1 ,'2017-03-08' , '09:20:00' , NULL
UNION ALL 
SELECT 39 , 1 ,'2017-03-10' , NULL , '18:04:00'
UNION ALL
SELECT 39 , 1 ,'2017-03-20' , '08:56:00' , '18:53:00'
UNION ALL
SELECT 39 , 1 ,'2017-03-21' , '08:52:00' , '18:10:00'
UNION ALL
SELECT 39 , 1 ,'2017-03-22' , '08:56:00' , '18:09:00'
UNION ALL
SELECT 39 , 1 ,'2017-03-23' , NULL , '18:05:00'

您的代码将是

DECLARE @cod_personal INT = 39
    ,@startDate DATE = '2017/03/01'
    ,@endDate DATE = '2017/03/23'

;WITH CTE AS (
    SELECT DATEADD(DD, number, @startDate) AS DATES
    FROM master.dbo.spt_values
    WHERE TYPE = 'P'
        AND DATEADD(DD, number, @startDate) <= @endDate
    )
SELECT ISNULL(RA.cod_personal, @cod_personal) AS cod_personal
    ,cod_schedule
    ,DATES AS date_mark
    ,check_in
    ,check_out
    ,CASE 
        WHEN date_mark IS NULL
            THEN 'LEFT'
        WHEN date_mark IS NOT NULL AND check_in IS NULL
            THEN 'LEFT IN'
        WHEN date_mark IS NOT NULL AND check_in IS NOT NULL AND check_out IS NOT NULL
            THEN 'OK'
        WHEN date_mark IS NOT NULL AND check_in IS NOT NULL AND check_in > '09:15:00'
            THEN 'LATE'
        ELSE 'LEFT'
        END AS CONDITION
FROM CTE C
LEFT JOIN ReportAssistence RA ON C.DATES = date_mark
WHERE ISNULL(RA.cod_personal, @cod_personal) = @cod_personal

结果将是

+--------------+--------------+------------+----------+-----------+-----------+
| cod_personal | cod_schedule | date_mark  | check_in | check_out | CONDITION |
+--------------+--------------+------------+----------+-----------+-----------+
|           39 | NULL         | 2017-03-01 | NULL     | NULL      | LEFT      |
|           39 | 1            | 2017-03-02 | NULL     | 18:10:00  | LEFT IN   |
|           39 | NULL         | 2017-03-03 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-04 | NULL     | NULL      | LEFT      |
|           39 | 1            | 2017-03-05 | NULL     | 18:02:00  | LEFT IN   |
|           39 | NULL         | 2017-03-06 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-07 | NULL     | NULL      | LEFT      |
|           39 | 1            | 2017-03-08 | 09:20:00 | NULL      | LATE      |
|           39 | NULL         | 2017-03-09 | NULL     | NULL      | LEFT      |
|           39 | 1            | 2017-03-10 | NULL     | 18:04:00  | LEFT IN   |
|           39 | NULL         | 2017-03-11 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-12 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-13 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-14 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-15 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-16 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-17 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-18 | NULL     | NULL      | LEFT      |
|           39 | NULL         | 2017-03-19 | NULL     | NULL      | LEFT      |
|           39 | 1            | 2017-03-20 | 08:56:00 | 18:53:00  | OK        |
|           39 | 1            | 2017-03-21 | 08:52:00 | 18:10:00  | OK        |
|           39 | 1            | 2017-03-22 | 08:56:00 | 18:09:00  | OK        |
|           39 | 1            | 2017-03-23 | NULL     | 18:05:00  | LEFT IN   |
+--------------+--------------+------------+----------+-----------+-----------+

答案 1 :(得分:1)

@ShakeerMirza答案是对的 - 这里是一个替代CTE,它不需要查询master数据库来构建连续日期表。 (将此作为答案而不是评论添加,因为格式很重要。)

;with cod (dates)
as
(
    select cast(@startdate as date) as dates
    union all
    select dateadd(day, 1, dates) as next_dt
    from cod
    where DATEADD(day, 1, dates) < @enddate
)
select * from cod

答案 2 :(得分:0)

完成商店程序!!!

在我的案例中,日期必须以文字形式输入, 因为我使用java而且我在我的POO和接口上有关于将date.util转换为date.sql的问题

USE [DB_Demo1]
GO
/****** Object:  StoredProcedure [dbo].[showMeReportAssistance]    Script Date: 5/04/2017 12:36:46 a. m. ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[showMeReportAssistance]

@cod_personal INT,
@startDate VARCHAR(10),
@endDate VARCHAR(10)

as
BEGIN
;WITH CTE AS (
    SELECT DATEADD(DD, number, CONVERT(datetime, @startDate, 103)) AS DATES
    FROM master.dbo.spt_values
    WHERE TYPE = 'P'
        AND DATEADD(DD, number, CONVERT(datetime, @startDate, 103)) <= CONVERT(datetime, @endDate, 103)
    )
SELECT ISNULL(RA.cod_personal, @cod_personal) AS cod_personal
    ,cod_schedule
    ,DATES AS date_mark
    ,check_in
    ,check_out
    ,CASE 
        WHEN date_mark IS NULL
            THEN 'LEFT'
        WHEN date_mark IS NOT NULL AND check_in IS NULL
            THEN 'LEFT IN'
        WHEN date_mark IS NOT NULL AND check_in IS NOT NULL AND check_out IS NOT NULL
            THEN 'OK'
        WHEN date_mark IS NOT NULL AND check_in IS NOT NULL AND check_in > '09:15:00'
            THEN 'LATE'
        ELSE 'LEFT'
        END AS CONDITION
FROM CTE C
LEFT JOIN ReportAssistence RA ON C.DATES = date_mark
WHERE ISNULL(RA.cod_personal, @cod_personal) = @cod_personal
END