【发布时间】:2012-12-21 19:04:05
【问题描述】:
我有一个查询要显示两个日期之间员工的考勤状态。
@FromDate 和 @ToDate 两个参数被传递到存储过程中。此存储过程有一个 CTE,其中填写了此期间之间的所有日期。这在以下查询中由 T 表示。另一个 CTE,即 TUI,包含 T 的所有日期以及来自另一个名为 USER_INFO 的表的所有相关 USER ID。
其他需要连接的表有:
表:USER_INFO
USER_ID INT P.K, DISPLAY_NAME Varchar
表:ATTDETAILS
inUserID INT P.K, dtAttendanceDate DateTime, inAttendanceStatusId INT F.K
表:Att_Status_Master
inAttendanceStatusId INT P.K, ATTStatus VARCHAR
上面的表Att_Status_Master 中的AttStatus 列包含值:Present, Absent 等。
以下代码的问题在于,它仅在特定日期存在任何AttStatus 时才给出结果。如果没有员工在特定日期标记出勤,则该日期不会出现在结果集中。
我希望显示所有日期,而不考虑 NULL 值。上面提到的 CTE T 将两个日期之间的所有日期提供给临时表#Results。现在我想为所有员工显示所有这些日期。
例如:
如上所示,日期 01/dec/2012 没有状态,但仍应显示在结果中。而对于下面的查询,它没有被显示。以下查询仅显示填充了AttStatus 的记录。
最终的存储过程代码如下:
@FromDate DateTime /* Input Parameter */
@ToDate DateTime /* Input Parameter */
If OBJECT_ID('tempdb..#Results',N'U') IS NOT NULL
DROP TABLE #Results
DECLARE @StartDate DateTime
DECLARE @EndDate DateTime
@StartDate = Convert(Varchar(25),@FromDate,112)
@EndDate = Convert(Varchar(25), (DateAdd(DAY,15,@FromDate)),112)
;With T (tempStoredDate)
AS (
select @StartDate
union all
select dateadd(day,1,tempStoredDate) from T where T.tempStoredDate < @EndDate
),
TUI AS
(
select T.tempStoredDate, UI.user_id, ui.display_name, dbo.GetEmployeeCode(UI.user_id) AS EmpCode from T
cross join user_info UI
)
select TUI.EmpCode, UI.user_id, UI.Display_Name, TUI.tempStoredDate, AD.dtAttendanceDate, ASM.AttStatus
INTO #Results From TUI
left outer join user_info UI
on TUI.user_id = UI.user_id
left outer join Att_Details AD
on UI.user_id = AD.inUserId
inner join Att_Status_Master ASM
on ASM.inAttendanceStatusId = AD.inAttendanceStatusId
where Convert(Varchar(25),dtAttendanceDate,112) = Convert(Varchar(25),tempStoredDate,112)
group by TUI.tempStoredDate,UI.user_id,UI.Display_Name,TUI.EmpCode,AD.dtAttendanceDate,AD.inAttendanceStatusId,ASM.AttStatus
我注意到由于 WHERE 子句,这种情况正在发生。如果我忽略 WHERE 子句,所有日期都可见,但 AttStatus 显示错误。
【问题讨论】:
-
你指的是哪个where子句?
-
你确定它不是 Att_Status_Master 的内部连接?缺少的行的状态为 NULL,不会通过连接条件
-
@NathanSkerl 我也试过 Left Join。
-
@bonCodigo 我指的是: where Convert(Varchar(25),dtAttendanceDate,112) = Convert(Varchar(25),tempStoredDate,112)
-
检查this SQL Fiddle - 它被简化了,但它清楚地表明:使用
INNER JOIN,您正在“过滤”不存在的数据,使用LEFT OUTER JOIN,您可以获得数据......
标签: sql-server sql-server-2005