Sql 缺少日期的左连接
我有一个数据表(Sql 缺少日期的左连接,sql,sql-server,join,Sql,Sql Server,Join,我有一个数据表(FACT.UnitData),其中有列(DayCalendarDate和saleqty),但缺少一些数据: DayCalendarDate SalesQty 2019-05-13 00:00:00.0000000 36 2019-05-11 00:00:00.0000000 105 2019-05-10 00:00:00.0000000 50 2019-05-09 00:00:00.0000000 30 2019-05-08 00:00:00.000000
FACT.UnitData
),其中有列(DayCalendarDate
和saleqty
),但缺少一些数据:
DayCalendarDate SalesQty
2019-05-13 00:00:00.0000000 36
2019-05-11 00:00:00.0000000 105
2019-05-10 00:00:00.0000000 50
2019-05-09 00:00:00.0000000 30
2019-05-08 00:00:00.0000000 22
我有另一个表(DIM.DayCalendar
),其中有一列(Date
)是连续的,因此没有丢失的日期:
Date
2019-05-13 00:00:00.0000000
2019-05-12 00:00:00.0000000
2019-05-11 00:00:00.0000000
2019-05-10 00:00:00.0000000
2019-05-09 00:00:00.0000000
2019-05-08 00:00:00.0000000
我想把这两个表合并起来,并用0.0填写FACT.UnitData
中缺少的日期(2019-05-12)。到目前为止,我有以下信息:
DECLARE @unit_id INT = 71907
DECLARE @location_id INT = 59
SELECT dc.Date, ud.SalesQty
FROM DIM.DayCalendar AS dc
LEFT JOIN FACT.UnitData AS ud
ON dc.Date = ud.DayCalendarDate
WHERE ud.UnitID = @unit_id AND ud.LocationID = @location_id
ORDER BY dc.Date DESC
但这并不能用0.0来填充缺失的日期(2019-05-12)
谢谢您的帮助。您是否只需要
coalesce()
还请注意,ORDER BY
使用日历日期,而不是参考值。毕竟,这将是NULL
,因此它的顺序不正确
DECLARE @unit_id INT = 71907
DECLARE @location_id INT = 59
SELECT dc.Date, ud.SalesQty
FROM DIM.DayCalendar AS dc
LEFT JOIN FACT.UnitData AS ud
ON dc.Date = ud.DayCalendarDate
WHERE ud.UnitID = @unit_id AND ud.LocationID = @location_id
ORDER BY dc.Date DESC
在我看到它的时间点(我没有看到NOLOCK,可能已经进行了其他编辑)的查询将在SQL中执行,如下所示:
首先,将处理作为dc的DIM.DayCalendar中的数据
此表上没有进行筛选,因此在此步骤中将检索所有行
接下来,处理将FACT.UnitData作为ud
的连接。作为LOJ,第一个表中的所有行保持不变(仍然没有过滤),在第二个表中找到的行将加入。这可能会导致第一个表中的行出现不止一次(即,第二个表中每个连接行出现一次)。更重要的是,如果在第二个表中找不到行,则它们的值将设置为NULL
接下来考虑WHERE子句:ud.UnitID=@unit\u id和ud.LocationID=@location\u id
。“ud”是第二个表,因此所有不符合这些条件的行都将被过滤掉。这意味着当找到空值时,where子句将解析为False,因此从第二个表中没有检索到数据的所有行都将被过滤掉
这就是您丢失日期的原因–外部联接成功,但所有“未找到数据”行都将被删除。下一个效果与使其成为内部联接的效果相同
最直接的修复方法是将filterig条件移动到join子句中,如下所示:
SELECT dc.Date, ud.SalesQty
FROM DIM.DayCalendar AS dc
LEFT JOIN FACT.UnitData AS ud
ON dc.Date = ud.DayCalendarDate
AND ud.UnitID = @unit_id
AND ud.LocationID = @location_id
ORDER BY dc.Date DESC
这将在第二个表中找到较少的联接行,但由于它是外部联接,因此第一个表中的所有行都将包含在结果集中
另一个版本是检查where子句中的NULL:
SELECT dc.Date, ud.SalesQty
FROM DIM.DayCalendar AS dc
LEFT JOIN FACT.UnitData AS ud
ON dc.Date = ud.DayCalendarDate
WHERE ud.UnitID = isnull(@unit_id, ud.UnitID)
AND ud.LocationID = isnull(@location_id, ud.LocationID)
ORDER BY dc.Date DESC
请注意,这可能会比第一个查询执行得稍差一些。这两个查询都有点难以阅读和理解,但对于复杂的查询,这种情况会发生。您确定吗?如果您按
c.Date
订购该怎么办?根据(NOLOCK)
查询提示,这看起来像SQL Server
,而不是MySQL
。您的标签正确吗?另外,您可能希望阅读此-(NOLOCK)
是一个SQL Server提示,因此我更改了该标记。话虽如此,你不应该使用它,除非你真的知道自己在做什么。@alex_lewis。要用什么填充值?了解左联接返回的内容:内部联接行加上由null扩展的不匹配的左表行。始终知道作为左连接的一部分,您需要什么样的内部连接。一个WHERE或ON,它要求在上的左联接删除任何由NULL扩展的行后右表列不为NULL,即只保留内部联接行,即“将左联接转换为内部联接”。你有,谢谢你的建议。然而,这似乎不起作用。我在服务器上只有读取权限,这是为什么呢?您应该只需要读取权限,而且查询肯定没有问题。请参阅此处的示例(除模式名称外无其他更改)@alex_lewis“这似乎不起作用”您这是什么意思?@MartinBrown。在SQL Server中,当第一个表达式比较复杂时,ISNULL()
具有更好的性能*(coalesce()
对其求值两次)。但是,coalesce()
既标准又更灵活(因为它接受两个以上的参数。@MartinBrown另一个区别是COALESCE
和ISNULL
也有不同的返回类型规则。COALESCE的返回类型将是具有最高优先级的表达式的类型,而ISNULL
的返回类型将是第一个参数的类型。ISNULL(CONVERT(位,0),0)
返回一位,但合并(CONVERT(位,0),0)
将返回一个int。在很多情况下,这可能是一个决定性因素,但在某些情况下,它可能会节省一到两次转换,或者令人头痛的是,在添加coalesce后,为什么您的位列突然变为int。非常感谢——与@GordonLinoff的答案完美结合使用(使用合并方法)。
SELECT dc.Date, ud.SalesQty
FROM DIM.DayCalendar AS dc
LEFT JOIN FACT.UnitData AS ud
ON dc.Date = ud.DayCalendarDate
WHERE ud.UnitID = isnull(@unit_id, ud.UnitID)
AND ud.LocationID = isnull(@location_id, ud.LocationID)
ORDER BY dc.Date DESC