2017-04-05 50 views
1

我在SQL Server中有一個表RRHH.ReportAssistence。所有數據都是從我的軟件中自動完成的,用於標記,並且該軟件完成該表。SQL Server:如果表中沒有條件,則選擇範圍內的每一天

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」顯示在時間欄「條件」 = LEFT,如果時間在「check_in」到09:15:00顯示「CONDITION」= LATE,如果小於09:15:00顯示「CONTIDION」= OK,如果沒有check_in「CONDITION」=左輸入, 如果沒有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  
+0

如何給ReportAssistence中不存在的日期提供cod_schedule? –

+0

我顯示的第一個表格是真實的,這些信息由軟件自動填充,關於「cod_schedule」是分配給與人員代碼相匹配的工作人員的時間表代碼 –

+1

備註:您應該**不要**使用存儲過程的'sp_'前綴。微軟已經保留了這個前綴以供自己使用(參見*命名存儲過程*)](http://msdn.microsoft.com/en-us/library/ms190669%28v=sql.105%29.aspx),以及你將來有可能冒着名字衝突的風險。 [這對你的存儲過程性能也是不利的](http://www.sqlperformance.com/2012/10/t-sql-queries/sp_prefix)。最好只是簡單地避免使用'sp_'並使用別的東西作爲前綴 - 或者根本沒有前綴! –

回答

1

您需要先根據傳遞給過程的日期生成日期列表。並做LEFT JOIN到您的實際表。通過向CASE提供您的條件來獲得您的CONDITION欄。

模式:

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 | 
+--------------+--------------+------------+----------+-----------+-----------+ 
+0

是的,但我認爲,而不是循環和遞歸CTE,最好使用存在數據庫中的表。 –

+0

是的,我只是想知道,因爲這似乎是某種教育數據庫的任務,是否可以安全地假定作者可以/應該查詢系統數據庫。 –

+0

你是對的。 :) @MaxSzczurek –

1

@ShakeerMirza的答案是正確的 - 這裏是一個替代CTE是不需要查詢master數據庫來構建表o f連續日期。 (因爲格式是很重要的添加這作爲一個答案,而不是評論。)

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

存儲過程DONE!

這是必要的日期在我的情況下,可以作爲文本輸入, 因爲我使用Java和我有問題的鑄造date.util到date.sql我POO和接口

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 
相關問題