我有一个类似的存储过程:
select
TransactionDate
from
(select
cast(TransactionDate as Date) as TransactionDate
from RetailTransaction) t
但是,这会使外部选择的TransactionDate
列为空,而RetailTransaction.TransactionDate
列不为空。
RetailTransaction.TransactionDate
定义/设计:
内部选择
外部选择:
即使添加了isnull
或coalesce
之后,SQL Server / SSMS仍然显示外部选择TransactionDate
列仍然可以为空。
select
TransactionDate
from
(select
isnull(cast(TransactionDate as Date), getdate()) as TransactionDate
from
RetailTransaction) t
如何使TransactionDate
列不可为空?
请注意,数据库位于兼容级别为100(SQL Server 2008)的Azure上。
编辑:
在外部选择上添加isnull
仍会使该列对外部嵌套查询为空:
答案 0 :(得分:3)
是的,对于不可为空的列显示为可为空的原因是因为您正在根据外部条件和其他条件进行外部选择。
在此表中,电子邮件不可为空列,现在,如果我在内部查询中提供Isnull条件,它将是这样。
现在,如果我不给出任何条件,它将是这样。
您也可以参考此链接以获取详细说明。
答案 1 :(得分:1)
在阅读您的评论后,我进行了一些挖掘和测试,即使我找不到有关它的官方文档,您也是正确的,并且强制转换为date可以使该值可为空,即使datetime不可为空。我什至尝试了使用datetimefromparts
创建日期数据类型的另一种方法,但这也改变了结果的无效性。
以我的看法,您有两个选择:
第一个选项是向表添加一个持久化的计算列,该列将保存交易日期的日期值。必须将其持久化为不可为空:
ALTER TABLE RetailTransaction
ADD TransactionDateOnly AS CAST(TransactionDate As Date) PERSISTED NOT NULL;
,然后您的查询如下所示:
SELECT TransactionDateOnly as TransactionDate
FROM RetailTransaction
另一种选择是声明一个带有不可为null的date列的表变量,选择强制转换结果,然后从表变量中进行选择:
DECLARE @Target AS TABLE
(
TransactionDate Date NOT NULL
)
INSERT INTO @Target(TransactionDate)
SELECT CAST(TransactionDate as Date)
FROM RetailTransaction) t
然后您的选择如下所示:
SELECT TransactionDate
FROM @Target
这两种方法都会使您获得一个不可为空的日期,但是我认为,持久化计算列选项可能会在select上产生更好的性能,因为它不需要额外的insert ... select。
答案 2 :(得分:0)
诀窍是将ISNULL放在外部查询上并添加别名,以免丢失名称
select
isnull(TransactionDate, GETDATE()) as TransactionDate
from (
select
Cast(TransactionDate as Date) as TransactionDate
from RetailTransaction
) t
这样,SQL将意识到该字段不能为null。这应该很好地通知任何ORM,该字段不应映射为可为空的类型。