为什么 SQL count(*) 与 SQL count(numeric) 存在行为差异

Why there is a behavior difference of SQL count(*) vs SQL count(numeric)

我知道 count(*) - 将 returns 包括空值在内的所有行的总数。 count(colName) - 将 returns colName 不为空的所有行的总数。

今天我的一所大学在 SQL 中遇到了 count() 的问题。他试图在应用一些日期过滤器后从视图中获取行数。

查看Return数据结构

 [Year]                 VARCHAR(4)        
,[Month]                VARCHAR(4)        
,AType                  VARCHAR(20)       
,PActualsID             INT               
,EID                    VARCHAR(12)       
,CID                    INT               
,CGId                   INT               
,EMargin                NUMERIC(17,3)     
,Period                 DATETIME          
,PLID                   INT               
,PCID                   INT               
,PSID                   INT               
,VPID                   INT               
,VSID                   INT               
,STID                   INT               

查询 1

SELECT * from vw_ActualAllocation_New
where   EntityId = '442105'       and 
        Period   >= '01-Jan-2017' AND  Period  < '01-Jan-2018'

这 returns 约 94 条记录。

查询 2

SELECT Count(*) from vw_ActualAllocation_New
where   EID = '442105'    and 
        Period   >= '01-Jan-2017' AND  Period  < '01-Jan-2018'

这returns一个错误

Msg 241, Level 16, State 1, Line 1 Conversion failed when converting date and/or time from character string.

查询 3

SELECT Count(EMargin) from vw_ActualAllocation_New
where   EID = '442105'    and 
        Period   >= '01-Jan-2017' AND  Period  < '01-Jan-2018'

这个returns我算94。

Please note that EMargin is a NUMERIC datatype and all other types such as int and varchar returns the same error.

请分享您对这两种行为之间差异的看法。

SQL 服务器环境:Microsoft SQL Server 2012 (Build 7601: Service Pack 1) (Hypervisor)

更新 - 查看代码

CREATE VIEW [dbo].[vw_ActualAllocation_New]
SELECT D.Year, D.Month, A.AType, A.PAID, D.EntityID, D.CustomerID
,B.CGId, SUM(A.EBITRMargin) AS EBITRMargin
,CONVERT(DATETIME,D.Month + '-01-' + D.Year) AS Period, D.PLID, D.PCID
,D.PSID, D.VPID, D.VSID,D.STID 
FROM  dbo.AAllocations AS A 
INNER JOIN dbo.PActuals AS D ON D.PActualsID = A.PActualsID AND D.Active = 1 
INNER JOIN dbo.Customer AS B ON D.CustomerID = B.CustomerID AND D.EntityID = 
B.EntityID 
INNER JOIN dbo.AStatus AS C ON  A.ASID = C.ASID
WHERE (A.Active = 1) AND (C.Active = 1) AND (C.Reference = 'Actuals') AND 
(C.Status = 1)
GROUP BY D.Year, D.Month, A.AType, A.PAID, D.EntityID, D.CustomerID, B.CGId, 
D.PLID, D.PCID, D.PSID, D.VPID, D.VSID, D.STID 

结论更新

根据Gordon的建议得出了结论,如果您觉得自己可能有其他想法,请post在这里 我还尝试将视图中的数据转换为新的 table 并且它工作正常。直接从视图访问时发生问题。视图生成发生在大量数据上,由于其巨大的规模和隐私协议,无法在此处 post 生成视图。感谢您理解我的局限并帮助我

问题最可能的原因是这行代码:

CONVERT(DATETIME, D.Month + '-01-' + D.Year) AS Period

在 SQL 服务器中,你不应该在没有指定格式或使用标准格式的情况下使用 CONVERT() 从字符串到日期(SQL 服务器首选 YYYYMMDD,但我认为YYYY-MM-DD 也可以接受。

在旧版本的 SQL 服务器中,您可以:

CONVERT(DATE, d.Year + RIGHT('00' + D.Month, 2) + '01') as period

此转换将始终有效。在较新的版本中,使用 datefromparts():

DATEFROMPARTS(d.Year, d.Month, 1) as Period

为什么会这样?我推测日期格式被解释为 DD-MM-YYYY 而不是 MM-DD-YYYY。换句话说,你认为的 2 月 1 日实际上是 1 月 2 日。

此外,实体“442105”的期间值都转换为合理的日期。 WHERE 子句过滤掉错误的值。问题在于其他实体和问题,正如 Damien 指出的那样,问题在于在执行引擎中评估值的位置。