Mah*_*vej 9 t-sql sql-server check-constraints user-defined-functions
我的查询:
INSERT into PriceListRows (PriceListChapterId,[No])
SELECT TOP 250 100943 ,N'2'
FROM #AnyTable
Run Code Online (Sandbox Code Playgroud)
此查询工作正常,并根据需要引发以下异常:
INSERT语句与CHECK约束"CK_PriceListRows_RowNo_Is_Not_Unqiue_In_PriceList"冲突.冲突发生在数据库"TadkarWeb",表"dbo.PriceListRows"中.
但是更改SELECT TOP 250为SELECT TOP 251(是!只需更改250到251!),查询成功运行,没有任何检查约束异常!
为何这种奇怪的行为?
注意:
我的检查约束是一种检查某种唯一性的函数.它查询约4个表.
我检查了SQL Server 2012 SP2和SQL Server 2014 SP1
**编辑1**
检查约束函数:
ALTER FUNCTION [dbo].[CheckPriceListRows_UniqueNo] (
@rowNo nvarchar(50),
@rowId int,
@priceListChapterId int,
@projectId int)
RETURNS bit
AS
BEGIN
IF EXISTS (SELECT 1
FROM RowInfsView
WHERE PriceListId = (SELECT PriceListId
FROM ChapterInfoView
WHERE Id = @priceListChapterId)
AND (@rowID IS NULL OR Id <> @rowId)
AND No = @rowNo
AND (@projectId IS NULL OR
(ProjectId IS NULL OR ProjectId = @projectId)))
RETURN 0 -- Error
--It is ok!
RETURN 1
END
Run Code Online (Sandbox Code Playgroud)
**编辑2 **检查约束代码(SQL Server 2012生成的内容):
ALTER TABLE [dbo].[PriceListRows] WITH NOCHECK ADD CONSTRAINT [CK_PriceListRows_RowNo_Is_Not_Unqiue_In_PriceList] CHECK (([dbo].[tfn_CheckPriceListRows_UniqueNo]([No],[Id],[PriceListChapterId],[ProjectId])=(1)))
GO
ALTER TABLE [dbo].[PriceListRows] CHECK CONSTRAINT [CK_PriceListRows_RowNo_Is_Not_Unqiue_In_PriceList]
GO
Run Code Online (Sandbox Code Playgroud)
**编辑3**
执行计划在这里:https://www.dropbox.com/s/as2r92xr14cfq5i/execution%20plans.zip?dl=0
**编辑4**
RowInfsView定义是:
SELECT dbo.PriceListRows.Id, dbo.PriceListRows.No, dbo.PriceListRows.Title, dbo.PriceListRows.UnitCode, dbo.PriceListRows.UnitPrice, dbo.PriceListRows.RowStateCode, dbo.PriceListRows.PriceListChapterId,
dbo.PriceListChapters.Title AS PriceListChapterTitle, dbo.PriceListChapters.No AS PriceListChapterNo, dbo.PriceListChapters.PriceListCategoryId, dbo.PriceListCategories.No AS PriceListCategoryNo,
dbo.PriceListCategories.Title AS PriceListCategoryTitle, dbo.PriceListCategories.PriceListClassId, dbo.PriceListClasses.No AS PriceListClassNo, dbo.PriceListClasses.Title AS PriceListClassTitle,
dbo.PriceListClasses.PriceListId, dbo.PriceLists.Title AS PriceListTitle, dbo.PriceLists.Year, dbo.PriceListRows.ProjectId, dbo.PriceListRows.IsTemplate
FROM dbo.PriceListRows INNER JOIN
dbo.PriceListChapters ON dbo.PriceListRows.PriceListChapterId = dbo.PriceListChapters.Id INNER JOIN
dbo.PriceListCategories ON dbo.PriceListChapters.PriceListCategoryId = dbo.PriceListCategories.Id INNER JOIN
dbo.PriceListClasses ON dbo.PriceListCategories.PriceListClassId = dbo.PriceListClasses.Id INNER JOIN
dbo.PriceLists ON dbo.PriceListClasses.PriceListId = dbo.PriceLists.Id
Run Code Online (Sandbox Code Playgroud)
Raz*_*col -1
您可能遇到了不正确的查询优化,但如果没有所有涉及的表中的数据,我们就无法重现该错误。
但是,对于此类检查,我建议使用触发器而不是基于函数的检查约束。在触发器中,您可以使用 SELECT 语句来调试它未按预期工作的原因。例如:
CREATE TRIGGER trg_PriceListRows_CheckUnicity ON PriceListRows
FOR INSERT, UPDATE
AS
IF @@ROWCOUNT>0 BEGIN
/*
SELECT * FROM inserted i
INNER JOIN RowInfsView r
ON r.PriceListId = (
SELECT c.PriceListId
FROM ChapterInfoView c
WHERE c.Id = i.priceListChapterId
)
AND r.Id <> i.Id
AND r.No = i.No
AND (r.ProjectId=i.ProjectId OR r.ProjectId IS NULL AND i.ProjectId IS NULL)
*/
IF EXISTS (
SELECT * FROM inserted i
WHERE EXISTS (
SELECT * FROM RowInfsView r
WHERE r.PriceListId = (
SELECT c.PriceListId
FROM ChapterInfoView c
WHERE c.Id = i.priceListChapterId
)
AND r.Id <> i.Id
AND r.No = i.No
AND (r.ProjectId=i.ProjectId OR r.ProjectId IS NULL AND i.ProjectId IS NULL)
)
) BEGIN
RAISERROR ('Duplicate rows!',16,1)
ROLLBACK
RETURN
END
END
Run Code Online (Sandbox Code Playgroud)
这样,您可以查看正在检查的内容并纠正您的视图和/或现有数据。