[更新:此问题描述了SQL Server 2019 累积更新 5 中已修复的错误。]
考虑以下重现示例(fiddle):
CREATE FUNCTION dbo.Repro (@myYear int)
RETURNS datetime
AS
BEGIN
IF @myYear <> 1990
BEGIN
RETURN NULL
END
DECLARE @firstOfYear datetime;
SET @firstOfYear = DATEFROMPARTS(@myYear, 1, 1);
IF DATEDIFF(day, @firstOfYear, @firstOfYear) <> 0
BEGIN
RETURN NULL
END
RETURN @firstOfYear
END
SELECT dbo.Repro(0);
Run Code Online (Sandbox Code Playgroud)
显然,如果输入是 ,该函数应该返回 1990 年 1 月的第一天1990
,NULL
否则返回。是的,我知道这DATEDIFF(day, @firstOfYear, @firstOfYear) <> 0
是一个荒谬的操作。这是一个演示潜在错误的mcve,而不是生产代码。
现在让我们SELECT dbo.Repro(0)
在 SQL Server 2017 和 SQL Server …
这个备受好评的 SO 答案建议将图像放在单独的表中,即使与另一个表只有 1:1 的关系:
如果您决定将图片放入 SQL Server 表中,我强烈建议使用单独的表来存储这些图片——不要将员工照片存储在员工表中——将它们保存在单独的表中。这样,Employee 表可以保持简洁和高效,假设您并不总是需要选择员工照片作为查询的一部分。
为什么?我的印象是SQL Server 只在表中存储一个指向某些专用 BLOB 数据结构的指针,那么为什么要手动创建另一个间接层呢?它真的能显着提高性能吗?如果是,为什么?
的ANSI SQL标准定义(第6.5章,集功能规范),用于空的结果集的集合函数以下行为:
COUNT(...) = 0
AVG(...) = NULL
MIN(...) = NULL
MAX(...) = NULL
SUM(...) = NULL
Run Code Online (Sandbox Code Playgroud)
为 AVG、MIN 和 MAX 返回 NULL 非常有意义,因为空集的平均值、最小值和最大值是未定义的。
然而,最后一个让我感到困扰:在数学上,空集的 SUM 是明确定义的:0
。使用 0,加法的中性元素,作为基本情况使一切保持一致:
SUM({}) = 0 = 0
SUM({5}) = 5 = 0 + 5
SUM({5, 3}) = 8 = 0 + 5 + 3
SUM({5, NULL}) = NULL = 0 + 5 + NULL
Run Code Online (Sandbox Code Playgroud)
定义SUM({})
为null
基本上使“无行”成为不适合其他行的特殊情况:
SUM({}) = NULL = NULL
SUM({5}) = 5 != …
Run Code Online (Sandbox Code Playgroud) 我们在 SQL Server 中遇到了一个有趣的问题。考虑以下重现示例:
CREATE TABLE #test (s_guid uniqueidentifier PRIMARY KEY);
INSERT INTO #test (s_guid) VALUES ('7E28EFF8-A80A-45E4-BFE0-C13989D69618');
SELECT s_guid FROM #test
WHERE s_guid = '7E28EFF8-A80A-45E4-BFE0-C13989D69618'
AND s_guid <> NEWID();
DROP TABLE #test;
Run Code Online (Sandbox Code Playgroud)
请暂时忘记s_guid <> NEWID()
条件似乎完全无用 - 这只是一个最小的重现示例。由于NEWID()
匹配某个给定常量的概率极小,因此每次都应评估为 TRUE。
但事实并非如此。运行此查询通常会返回 1 行,但有时(非常频繁,超过 10 次中的 1 次)返回 0 行。我已经在我的系统上使用 SQL Server 2008 复制了它,您可以使用上面链接的小提琴 (SQL Server 2014) 在线复制它。
查看执行计划显示查询分析器显然将条件拆分为s_guid < NEWID() OR s_guid > NEWID()
:
...这完全解释了为什么它有时会失败(如果第一个生成的 ID 小于给定的 ID,而第二个生成的 ID 大于给定的 ID)。 …
该sp_getapplock存储过程有以下返回值:
0:同步成功授予锁。
1:等待其他不兼容的锁释放后,成功授予锁。
-1:锁定请求超时。
-2:锁定请求被取消。
-3:锁定请求被选为死锁牺牲品。
-999:表示参数验证或其他调用错误。
我正在编写一个用于调用sp_getapplock
我们的数据访问层的包装器,我想知道在什么情况下可以返回 -2,以便我可以抛出一个描述性和有用的异常。-1 和 -3 的返回值的含义很明显,我可以轻松创建导致返回这些值的测试条件。我将如何设法获得 -2 的返回值?
我们有运行 SQL Server(2008 SP4 和 2016 SP1)的 PC,它们经常断电。显然,这有时会导致 SQL Server 数据库的(索引)损坏,我们需要稍后恢复。
我知道 SQL Server 不是为这种情况设计的,正确的解决方案是修复断电的原因(如果您好奇,请在下面详细介绍)。尽管如此,我可以设置 SQL Server 中的任何调整选项来降低断电时数据库损坏的风险吗?
背景:“PC”是安装在叉车上的 Windows 平板电脑。当用户关闭叉车时,平板电脑就会断电。我们曾尝试教用户在关闭叉车之前正确关闭 Windows,但失败了(可能是因为在大多数情况下只是将其关闭“有效”)。我们目前还在研究其他选项,例如添加一个 UPS,它会在断电时向平板电脑发出信号关闭。
我知道我可以使用sys.fn_my_permissions
以下方法查询有效权限:
USE myDatabase;
SELECT * FROM fn_my_permissions('dbo.myTable', 'OBJECT')
entity_name | subentity_name | permission_name
------------------------------------------------
dbo.myTable | | SELECT
dbo.myTable | | UPDATE
...
Run Code Online (Sandbox Code Playgroud)
这告诉我当前用户myTable
在数据库中是否具有 SELECT、INSERT、UPDATE 等权限myDatabase
。
是否可以很容易地找出为什么用户拥有这些权限?例如,我希望有一个fn_my_permissions_ex
输出附加reason
列的函数:
USE myDatabase;
SELECT * FROM fn_my_permissions_ex('dbo.myTable', 'OBJECT')
entity_name | subentity_name | permission_name | reason
------------------------------------------------------------------------------------------------------------------------------------
dbo.myTable | | SELECT | granted to database role public
dbo.myTable | | UPDATE | member of group MYDOMAIN\Superusers, which belongs to database role db_datawriter
... …
Run Code Online (Sandbox Code Playgroud) 在一些 SQL Server 开发人员中,普遍认为NOT IN
速度非常慢,应该重写查询,以便它们返回相同的结果,但不要使用“evil”关键字。(示例)。
这有什么道理吗?
例如,SQL Server 中是否存在一些已知错误(哪个版本?)导致使用NOT IN
的查询比使用的等效查询具有更差的执行计划
LEFT JOIN
结合了NULL
支票或(SELECT COUNT(*) ...) = 0
在WHERE
条款中?我有一张桌子
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
Run Code Online (Sandbox Code Playgroud)
和一个 T-SQL 布尔表达式,它可以计算为 TRUE、FALSE 或(由于 SQL 的三元逻辑)UNKNOWN:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Run Code Online (Sandbox Code Playgroud)
如果我想获得所有其他记录,我不能简单地否定表达式
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Run Code Online (Sandbox Code Playgroud)
我知道为什么会发生这种情况(三元逻辑),并且我知道如何解决这个特定问题。
我知道我可以使用myField = 'someValue' AND NOT myField IS NULL
并且我得到一个永远不会产生 UNKNOWN 的“可逆”表达式:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 …
Run Code Online (Sandbox Code Playgroud) 让我说出显而易见的拳头:我完全理解浮点类型不能准确表示十进制值。这不是关于那个!尽管如此,浮点计算应该是确定性的。
既然这已经解决了,让我向您展示我今天观察到的奇怪案例。我有一个浮点值列表,我想总结一下:
CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);
SELECT STR(SUM(#someFloats.val), 30, 15) FROM #someFloats;
DROP TABLE #someFloats;
-- yields:
-- 13.600000000000001
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都很好 - 这里没有惊喜。我们都知道1.2
不能用二进制表示来精确表示,所以“不精确”的结果是意料之中的。
现在,当我左加入另一个表时,会发生以下奇怪的事情:
CREATE TABLE #A (a int);
INSERT INTO #A (a) VALUES (1), (2);
CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);
SELECT #A.a, STR(SUM(#someFloats.val), 30, 15)
FROM #someFloats LEFT JOIN …
Run Code Online (Sandbox Code Playgroud) sql-server ×9
aggregate ×1
blob ×1
condition ×1
crash ×1
debugging ×1
except ×1
functions ×1
locking ×1
null ×1
optimization ×1
performance ×1
permissions ×1
security ×1
sql-standard ×1