TL;博士; SQL Server 允许标量 UDF 在架构绑定时递归调用自身,但仅在使用语法进行更改时才这样做,这是否是一个错误CREATE OR ALTER?或者是其他语法被禁止的错误?
一个简单的递归标量 UDF 可以构造如下
CREATE FUNCTION dbo.Try1 (@i int)
RETURNS int
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try1(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
只要这不是架构绑定的,那么这是允许的。
让我们尝试模式绑定它,我们会做
CREATE FUNCTION dbo.Try2 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try2(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
没有。
Cannot find either column "dbo" or the user-defined function
or aggregate "dbo.Try2", or the name is ambiguous
Run Code Online (Sandbox Code Playgroud)
不使用递归创建它然后更改它
CREATE OR ALTER …Run Code Online (Sandbox Code Playgroud) 该条款中是否存在未记录的限制OUTPUT,或者这是一个错误?
给出下表:
CREATE TABLE t1 (SomeId int, flag bit, value int);
Run Code Online (Sandbox Code Playgroud)
我想在UPDATE语句中使用计算值,然后使用OUTPUT输出该值。请注意,计算值未在该部件中使用SET,这可能允许通过输出左侧列来解决问题。
以下工作正常,它是一个完美标准的可更新子查询(派生表)。
UPDATE subT1
SET flag = 1
OUTPUT inserted.SomeValue
FROM (
SELECT *,
SomeValue = t1.value + 123
FROM t1
) subT1;
Run Code Online (Sandbox Code Playgroud)
然而使用窗口函数会出现一个奇怪的错误:
UPDATE subT1
SET flag = 1
OUTPUT inserted.Sum
FROM (
SELECT *,
Sum = SUM(t1.value) OVER (PARTITION BY t1.SomeId)
FROM t1
) subT1;
Run Code Online (Sandbox Code Playgroud)
Msg 404 Level 16 State 1 Line 3
The column reference "inserted.Sum" is not …Run Code Online (Sandbox Code Playgroud) 我想交换表中两列的值,我发现在 SQL 中我们可以通过使用 Update 来做到这一点:
update the_table set first_name = last_name, last_name = first_name;
Run Code Online (Sandbox Code Playgroud)
它有效但我想知道 SQL 如何能够做到这一点而不覆盖其他列中的列中的数据?
我先说这是来自 Stack Overflow 上一个未回答问题的交叉帖子。
我这样做并不是为了获得对这个问题的更多看法,我希望 DBA 社区分享他们对这是否可能是 SQL Server 中的错误的看法。我认为 SO 社区没有专业知识来决定这一点,所以我在这里重新发布。
假设我有一个 table T,并且我有一个索引视图V:
CREATE TABLE dbo.T (id int PRIMARY KEY, b bit NOT NULL, txt varchar(20));
GO
CREATE VIEW dbo.V
WITH SCHEMABINDING AS
SELECT T.Id, T.txt
FROM dbo.T AS T
WHERE T.b = 1;
GO
CREATE UNIQUE CLUSTERED INDEX idx_V ON dbo.V (Id);
Run Code Online (Sandbox Code Playgroud)
在这个简单的例子中,它基本上只是一个过滤索引,但它也可以有连接等。
我现在想在Twhere 中选择一些行,这里b = 1的过滤视图非常有用,我在标准上所以必须使用NOEXPAND(或者它对于视图匹配来说太复杂了):
SELECT Id, txt
FROM V WITH (NOEXPAND);
Run Code Online (Sandbox Code Playgroud)
这很好用。
现在我想将这些行更新为某个值。该视图符合可更新条件,因此我可以执行以下操作: …
我很难弄清楚如何实现这一目标。我知道如何用 C# 实现它,但不知道如何用 SQL 实现。
假设我有下表:
| ID | 姓名 | 路由ID |
|---|---|---|
| 1 | 鲍勃 | 1001 |
| 2 | 鲍勃 | 1002 |
| 3 | 安娜 | 1001 |
| 4 | 吉姆 | 1001 |
| 5 | 伊莱 | 1001 |
我想返回整个表,并用一个额外的列显示routeID按名称出现的总次数,所以where name='Bob'看起来像:
| ID | 姓名 | 路由ID | 全部的 |
|---|---|---|---|
| 1 | 鲍勃 | 1001 | 4 |
| 2 | 鲍勃 | 1002 | 1 |
但是,如果我写类似的东西
declare @ct as nvarchar(5)
set @ct = (SELECT COUNT(RouteId) from <table>)
select *, @ct
from <table>
where name = 'Bob'
Run Code Online (Sandbox Code Playgroud)
我得到所有路线 ID 的总数,而不仅仅是行中显示的路线 ID。
我尝试查看计算列,但据我所知它不支持这种类型的查询。
有人能指出我正确的方向吗?
我尝试使用查询重建数据库的所有索引,
USE [DB_Name];
GO
DECLARE @TableName VARCHAR(255)
DECLARE @sql NVARCHAR(500)
DECLARE TableCursor CURSOR FOR
SELECT '['+OBJECT_SCHEMA_NAME([object_id])+']'+'.'+name AS TableName
FROM sys.tables
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'ALTER INDEX ALL ON ' + @TableName + ' REBUILD'
PRINT @sql
EXEC (@sql)
FETCH NEXT FROM TableCursor INTO @TableName
END
CLOSE TableCursor
DEALLOCATE TableCursor
GO
Run Code Online (Sandbox Code Playgroud)
该查询执行了大约 3.5 小时,然后抛出错误消息,指出磁盘空间不足,这不是真的,但可能是数据库达到了其大小限制。
但唯一的问题是数据库的大小实际上增长了几乎 100%,而没有重建任何索引。我选择重建的主要原因是大多数索引碎片超过75%。
现在,不幸的是,从备份恢复不是一个选择,因为我们已经写入了新数据,而且已经过去了几个小时。
再次使用足够的磁盘空间进行重建可以解决问题吗?如果是这样,我是否仍然遵循当前数据库空间 1.5 倍的经验法则?
给出以下两个表:
CREATE TABLE SalesLedger (
Id int PRIMARY KEY IDENTITY,
Date date NOT NULL,
Total decimal(38,18),
INDEX IX (Date, Total)
);
CREATE TABLE Purchases (
Id int PRIMARY KEY IDENTITY,
Date date NOT NULL,
Total decimal(38,18),
INDEX IX (Date, Total)
);
Run Code Online (Sandbox Code Playgroud)
以及下面的视图
CREATE VIEW ViewMetrics
AS
Select
Date,
'Sale' as Metric,
Total as Value
From SalesLedger
UNION ALL
Select
Date,
'Purchase' as Metric,
Total as Value
From Purchases;
Run Code Online (Sandbox Code Playgroud)
以下查询使用一Concatenation Sort对:
Select SUM(Value) as Sales, Date
from ViewMetrics …Run Code Online (Sandbox Code Playgroud) 首先,可更新的 CTE、派生表或视图可以直接作为目标UPDATE,即使它具有多个基表,只要所有列都来自同一源表。
DELETE但即使仅选择一个表中的列,它们也不能成为 a 的目标。
Msg 4405 Level 16 State 1
View or function 'x' is not updatable because the modification affects multiple base tables.
Run Code Online (Sandbox Code Playgroud)
为了绕过这个限制,我尝试MERGE对虚拟表使用 a 。(显然,这个简单的示例可以使用DELETE...WHERE EXISTS或通过将一个表作为合并源来编写,但这一点是正确的。使用了原始示例,ROW_NUMBER因此这些是不可能的。)
WITH Joined AS (
SELECT t1.*
FROM t1
JOIN t2 ON t2.id1 = t1.id1
)
MERGE Joined
USING (VALUES(0)) v(dummy) ON 1=0
WHEN NOT MATCHED BY SOURCE THEN DELETE;
Run Code Online (Sandbox Code Playgroud)
这实际上是被允许的。但我发现被修改的表并不依赖于所选择的列或其顺序。这完全取决于表的连接顺序。
在我看来,这似乎是完全错误的行为。
实验THEN UPDATE显示了更明智的行为:它取决于子句中使用的列THEN UPDATE,与普通语句相同 …
我有一个 SSIS 包,我想将其作为作业运行。平面文件源位于服务器 A 上,而包和作业位于服务器 B 上。
当我运行执行 SSIS 包的作业时,出现错误:
错误代码 0xC020200E 无法打开数据文件
但我可以在 SSMS 中手动执行部署的包,并且它执行成功。我发现这是由于服务器 B 的 NT SERVICE\MSSQLSERVER 服务帐户无权访问服务器 A 上的文件夹造成的。
为了测试这一点,我在服务器 B 上创建了一个测试文件夹,并让 SSIS 包在其中查找。然后,我授予 NT SERVICE\MSSQLSERVER 对服务器 B 上的文件夹的完全访问权限。作业执行成功并且包运行,但是当我尝试向服务器 A 上的文件夹授予 NT SERVICE\MSSQLSERVER 权限时,我在位置选项卡,我无法访问 NT SERVICE\MSSQLSERVER 服务帐户。
我尝试过映射网络驱动器,但这没有帮助。文件每天早上自动上传到服务器 A,文件夹必须保留在服务器 B 上。
我在使用和不使用 OPTION (RECOMPILE) 的情况下执行了相同的查询。当我比较这两个计划时,我看到的一个主要区别是,没有选项重新编译的计划显示了很多 ComputeScalar 运算符,而另一个则没有。
以下是两个计划:
不带选项重新编译:https://www.brentozar.com/pastetheplan/ ?id=S1OcZGi85 带选项重新编译:https://www.brentozar.com/pastetheplan/ ?id=ryJAfMsL5
为什么一个计划使用大量计算标量,而另一个计划则不使用?不带选项重新编译的查询需要近 4 分钟才能执行。计算标量操作是否导致速度缓慢?
sql-server ×9
t-sql ×2
update ×2
count ×1
delete ×1
functions ×1
jobs ×1
maintenance ×1
merge ×1
network ×1
optimization ×1
permissions ×1
recompile ×1
recursive ×1
restore ×1
size ×1
ssis ×1
where ×1