在日期范围之间显示结果或在选择标准之间显示空值?

Show results between daterange or show null values between selection criteria?

我正在尝试获取 return 结果的报告,但目前得到 incorrect/inconsistent 结果,这让我有点头疼。

我正在使用的查询的一个非常简单的片段如下所示。

SELECT OCRD.CardName, OINV.DocTotal
FROM OCRD LEFT OUTER JOIN OINV ON OCRD.CardCode = OINV.CardCode
WHERE OINV.DocDate >= 'DATEFROM' AND OINV.DocDate <= 'DateTO'

如您所料,这会 return、客户名称和文档值在定义的日期范围内。但是,我还想包含也出现在日期范围内的 NULL 值?

(它背后的想法,是一个很好的简单报告,customer/spend 在一个日期范围内)。

如果我尝试 return NULL 值,它仅显示数据库中整个日期范围内的 NULL 值。有没有合理的方式让我获得这些信息?


编辑上面的数据,希望能解释我得到的结果和我想要实现的结果...我的销售价值来自 OINV.DocTotal,日期范围来自 OINV.DocDate... 使用以下数据;我假设我正在尝试显示“NULL”值或“2019”日期。

A) - 2018 年 - 销售额 100 英镑 | 2019 年 - 销售额 100 英镑 | 2020 年 - 销售额 100 英镑

以上显示的值为 100 英镑,因为 2019 年的销售额为 100 英镑。这太完美了,我希望数据会如何显示。

B) 2018 年 - NULL 销售额 | 2019 年 - NULL 销售额 | 2020 年 - 空销售额

以上将 return 一个“NULL”值;由于客户尚未消费,因此属于“NULL”类别。如上所述,这就是我希望 Null 数据显示的方式。

C) 2018 年 - 100 英镑销售额 | 2019 年 - NULL 销售额 | 2020 年 - £50 销售额

上面一行是我的问题;因为我的查询正在查找 2019 年的日期或 NULL 值,所以它根本没有显示任何内容。 (因为一个数据存在于我的日期范围之外,并且没有2019年范围内的值)这是否有意义?

--- 进一步编辑 ----

如下所示;在我的报告中,如果我将日期范围设置为 2019 年,则 2x 值“NULL”和“06/08/2018”将从我的报告中消失。就好像客户不存在一样。 我只是想让它表明它们确实存在,只是在 2019 年还没有购买。

对于“NULL”值,我假设您指的是 OCRD 中的所有行,即使没有匹配项也是如此。如果是这种情况,您可以使用 LEFT JOIN:

SELECT OCRD.CardName, OINV.DocTotal
FROM OCRD LEFT JOIN
     OINV 
    ON OCRD.CardCode = OINV.CardCode AND
        OINV.DocDate >= 'DATEFROM' AND OINV.DocDate <= 'DateTO';

注意:如果 'DATEFROM''DATETO' 是从应用程序传入的,您应该使用参数。您不应该使用参数值修改查询字符串。

如果我是正确的,NULL 可能在 DocDate 列中,并且您想将它们包含在结果集中。为此,您可以试试这个:

SELECT OCRD.CardName, ISNULL(OINV.DocTotal, 0) DocTotal
FROM OCRD 
LEFT OUTER JOIN OINV ON OCRD.CardCode = OINV.CardCode
WHERE ISNULL(OINV.DocDate, 'DATEFROM') >= 'DATEFROM' AND OINV.DocDate <= 'DateTO'

不是最干净的结果,但这是我设法为我工作的查询。我在其中添加了“类型”字段,这样您就可以看到我为每个查询尝试实现的结果。

SELECT 'Range' AS 'Type', T0.CardCode, T1.DocTotal, T1.DocDate 
FROM OCRD T0 LEFT OUTER JOIN OINV T1 ON T1.CardCode = T0.CardCode 
WHERE T1.DocDate >= '2019-01-01' and T1.DocDate <= '2019-12-31'
UNION ALL

SELECT 'Null' AS 'Type', T0.CardCode, T1.DocTotal, T1.DocDate 
FROM OCRD T0 LEFT OUTER JOIN OINV T1 ON T1.CardCode = T0.CardCode 
WHERE T1.DocDate  IS NULL
UNION ALL

SELECT 'OutRange' AS ' Type', T0.CardCode, '0' AS 'DocTotal', T1.DocDate 
FROM OCRD T0 LEFT OUTER JOIN OINV T1 ON T1.CardCode = T0.CardCode
WHERE (T1.DocDate < '2019-01-01' OR T1.DocDate > '2019-12-31')

ORDER BY [TYPE]
`

如果将日期筛选器移到联接条件中,您将看到所需的结果。从不消费的客户将与消费超出预期范围的客户完全相同。

您会在整个 Stack Overflow 中看到这个特殊问题。它归结为对外部连接的内侧使用 where 子句。将条件移动到连接中会更改应用连接期间而不是之后应用的行为。

SELECT OCRD.CardName, OINV.DocTotal
FROM OCRD LEFT OUTER JOIN OINV ON OCRD.CardCode = OINV.CardCode
    OINV.DocDate >= 'DATEFROM' AND OINV.DocDate <= 'DateTO'

您也可以通过这种方式更明确地首先应用过滤器:

with FilteredInvoices as (
    SELECT * FROM OINV 
    OINV.DocDate >= 'DATEFROM' AND OINV.DocDate <= 'DateTO'
)
SELECT OCRD.CardName, OINV.DocTotal
FROM OCRD LEFT OUTER JOIN FilteredInvoices OINV ON
    ON OCRD.CardCode = OINV.CardCode;