此Sql Server查询中的CTE语法有什么问题?
有人能解释为什么SQLServer抱怨WITH子句的语法吗 谢谢你的帮助此Sql Server查询中的CTE语法有什么问题?,sql,sql-server,tsql,Sql,Sql Server,Tsql,有人能解释为什么SQLServer抱怨WITH子句的语法吗 谢谢你的帮助 CREATE TABLE TestTable1 ( Id int not null, Version int not null constraint d_Ver default (0), [Name] nvarchar(50) not null, CONSTRAINT pk_TestTable1 PRIMARY KEY (Id, Version) ); GO CREATE TRIGGE
CREATE TABLE TestTable1 (
Id int not null,
Version int not null constraint d_Ver default (0),
[Name] nvarchar(50) not null,
CONSTRAINT pk_TestTable1 PRIMARY KEY (Id, Version)
);
GO
CREATE TRIGGER trg_iu_UniqueActiveName
ON [dbo].[TestTable1]
AFTER INSERT, UPDATE
AS
IF(UPDATE([Name]))
BEGIN
IF(
(
WITH MaxVers AS
(SELECT Id, Max(Version) AS MaxVersion
FROM [dbo].[TestTable1]
GROUP BY Id)
SELECT Count(1)
FROM [dbo].[TestTable1] t
INNER JOIN MaxVers ON t.Id = MaxVers.Id AND t.Version = MaxVers.MaxVersion
WHERE t.[Name] = inserted.[Name]
)
> 0
)
BEGIN
DECLARE @name nvarchar(50)
SELECT @name = [Name] FROM inserted;
RAISERROR('The name "%s" is already in use.', 16, 1, @name);
END
END;
GO
编辑2:
对于任何好奇的人,这里是CTE版本,包含了下面所有的好评论。我想我将切换到子查询方法,以便按照建议使用EXISTS
CREATE TRIGGER trg_iu_UniqueActiveName
ON [dbo].[TestTable1]
AFTER INSERT, UPDATE
AS
IF(UPDATE([Name]))
BEGIN
DECLARE @cnt [int];
WITH MaxVers AS
(SELECT Id, Max(Version) AS MaxVersion
FROM [dbo].[TestTable1]
GROUP BY Id)
SELECT @cnt = COUNT(1)
FROM [dbo].[TestTable1] t
INNER JOIN MaxVers ON t.Id = MaxVers.Id AND t.Version = MaxVers.MaxVersion
INNER JOIN [inserted] i ON t.[Id] = MaxVers.[Id]
WHERE t.[Name] = i.[Name] AND NOT [t].[Id] = [i].[Id] ;
IF( @cnt > 0)
BEGIN
DECLARE @name nvarchar(50)
SELECT @name = [Name] FROM inserted;
RAISERROR('The name "%s" is already in use by an active entity.', 16, 1, @name);
ROLLBACK TRANSACTION;
END
END;
GO
编辑3:这是存在的版本说明,我认为错误处理部分中的select无法正确处理多条插入的记录:
CREATE TRIGGER trg_iu_UniqueActiveName
ON [dbo].[TestTable1]
AFTER INSERT, UPDATE
AS
IF(UPDATE([Name]))
BEGIN
IF(EXISTS (
SELECT t.Id
FROM [dbo].[TestTable1] t
INNER JOIN (
SELECT Id, Max(Version) AS MaxVersion
FROM [dbo].[TestTable1]
GROUP BY Id) maxVer
ON t.[Id] = [maxVer].[Id] AND [t].[Version] = [maxVer].[MaxVersion]
INNER JOIN [inserted] i ON t.[Id] = MaxVer.[Id]
WHERE [t].[Name] = [i].[Name] AND NOT [t].[Id] = [i].[Id]
))
BEGIN
DECLARE @name nvarchar(50)
SELECT @name = [Name] FROM inserted;
RAISERROR('The name "%s" is already in use by an active entity.', 16, 1, @name);
ROLLBACK TRANSACTION;
END
END;
GO
我认为不能将CTE用于内部查询 将此用作解决方法:
DECLARE @cnt int;
WITH MaxVers AS
(SELECT Id, Max(Version) AS MaxVersion
FROM [dbo].[TestTable1]
GROUP BY Id)
SELECT @cnt = Count(1)
FROM [dbo].[TestTable1] t
INNER JOIN MaxVers ON t.Id = MaxVers.Id AND t.Version = MaxVers.MaxVersion
WHERE t.[Name] = inserted.[Name];
IF @cnt > 0
BEGIN
DECLARE @name nvarchar(50)
SELECT @name = [Name] FROM inserted;
RAISERROR('The name "%s" is already in use.', 16, 1, @name);
END
我唯一能理解的是,语句Transact-SQL引用意味着不能在IF语句中使用CTE 顺便说一句,您还有两个错误:1插入的伪表未包含在第一个子查询中,即使您在WARE子句中引用了它。2您的触发器假定插入或更新一行。可能存在多个重复名称,但raiserror将只报告其中一个 编辑并避免选择计数*…>存在时,选择*。。。。将要执行的操作可以在第一行停止 编辑2个垃圾。SQL Server触发器默认为after触发器。因此,当触发器触发时,您正在检查其存在性的行已存在于表中:
CREATE TRIGGER trg_iu_UniqueActiveName
ON [dbo].[TestTable1]
AFTER INSERT, UPDATE
AS
IF(UPDATE([Name]))
BEGIN
IF EXISTS
(
SELECT *
FROM [dbo].[TestTable1] t
INNER JOIN inserted i on i.[NAME] = t.[NAME]
INNER JOIN (SELECT Id, Max(Version) AS MaxVersion
FROM [dbo].[TestTable1]
GROUP BY Id) MaxVers ON t.Id = MaxVers.Id AND t.Version = MaxVers.MaxVersion
)
BEGIN
DECLARE @name nvarchar(50)
SELECT @name = [Name] FROM inserted;
RAISERROR('The name "%s" is already in use.', 16, 1, @name);
END
END;
GO
insert into testTable1 (name) values ('Hello')
结果:
Msg 50000, Level 16, State 1, Procedure trg_iu_UniqueActiveName, Line 20
The name "Hello" is already in use.
(1 row(s) affected)
另外,raiserror不会执行回滚,因此该行仍然存在。似乎不喜欢IF中的WITH语句 请尝试以下SQL:
SELECT COUNT(1)
FROM TestTable1 t1
WHERE t.Name = (SELECT [Name] FROM inserted)
AND t.Version = (SELECT MAX(Version) FROM TestTable1 t2 WHERE t2.Id = t.Id)
在我看来要简单得多。但是,这并不能解释插入表中的多行。将其更改为IN而不是an=可能会做到这一点
正如其他人所指出的,有时在WITH语句的from中放置分号是有效的,但在本例中我无法将其设置为。为什么不将CTE select表达式移动到内部联接中的子select?您应该使用EXISTS而不是Count>0>0。。。。嗯。。。您是否正在将CTE与0进行比较?您的触发器未被写入以正确处理多行更新,这可以通过从插入中选择@name=[name]来证明;id是标识列吗?那你为什么需要按id分组呢?谢谢你指出EricZ的身份。这是一个打字错误。看起来你是对的,不允许在那个位置使用。谢谢