我想创建一个唯一的索引视图,这样,如果将任何两个非空Location
分配给同一个Id
,那么它将违反索引并且不允许它们。
我像这样开始我的观点
-- This is what I wish I could do but its wrong
SELECT Id, Location, COUNT(*) as Count, COUNT(Location) as LocationCount
FROM #X
GROUP BY Id, Location
ORDER BY Id, Location
这不起作用,因为存在具有单个ID的位置具有NULL位置和非null位置的位置,这些位置根据业务规则是有效的,但根据分组重复了该ID。
这表明:
DROP TABLE IF EXISTS #X
SELECT *
INTO #X
FROM (
SELECT 1 as Id, 1 as Location
UNION
Select 1 as Id, NULL as Location
UNION
Select 2 as Id, NULL as Location
UNION
Select 3 as Id, 2 as Location
) X
-- This is what I wish I could do but its wrong
SELECT Id, Location, COUNT(*) as Count, COUNT(Location) as LocationCount
FROM #X
GROUP BY Id, Location
ORDER BY Id, Location
结果:
所需:
由于ID是重复的,因此无法将其作为索引视图。
我想要的只是使用AVG或MAX或忽略NULL的东西即可完成:
SELECT Id, AVG(Location) as Location, COUNT(*) as Count, COUNT(Location) as LocationCount
FROM #X
GROUP BY Id
ORDER BY Id, Location
但这不起作用,因为在索引视图中不允许AVG
,而且还因为它仅在Id
上分组,因此,如果将两个非null分配给单个ID,例如6和8,它将返回两者的平均值(7)而不是不允许它。
因此我想到了一个想法,我可以制作两个唯一的视图,一个用于null,一个用于非null,然后创建第三个视图,根据我想要的逻辑将它们组合在一起。这项工作可行,但是似乎可以完成我想要的事情,并且在使用视图时需要更多的开销和计算/处理,但是比没有索引视图要好:
;WITH IndexableViewNonNulls AS (
SELECT Id, Location, COUNT(*) as Count
FROM #X
WHERE Location IS NOT NULL
GROUP BY Id, Location
), IndexableViewNulls AS (
SELECT Id, Location, COUNT(*) as Count
FROM #X
WHERE Location IS NULL
GROUP BY Id, Location
), CTE AS (
SELECT *, Count as LocationCount
FROM IndexableViewNonNulls
UNION ALL
SELECT *, 0 as LocationCount
FROM IndexableViewNulls
)
SELECT
Id
,AVG(Location) as Location
,SUM(Count) as Count
,SUM(LocationCount) as LocationCount
FROM CTE
GROUP BY Id
这是完整的小提琴:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=f3df7c4b5703e9270ea1efe9bef5c152
编辑:这是另一个带有索引视图的小提琴。请注意,插入NULL会违反唯一索引,但是我不希望这样做。我只希望在所有两个非null的同时保持视图不变的情况下违反该规则(如果ALL为null,则位置显示NULL,如果存在1个或多个位置,则位置显示
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=544b5983bf25cd9c2ff1f55d68bd34d8
编辑2:这是我的解决方案,使用2个索引视图和1个普通视图将它们放在一起:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b8cf5ff638305a0d228c856b6391246d
编辑3:#X表不是普通表,仅在表上添加索引不是有效的解决方案。在实际的场景中,表#X本身就是视图,因此解决方案必须使用索引视图
答案 0 :(得分:0)
我认为您可以创建过滤索引:
create unique index unq_index_x_id_location on x(id, location) where location is not null;
如果您只想满足此约束的视图,那么我认为这可以满足您的要求:
SELECT Id, MIN(Location) as location
FROM #X
GROUP BY Id
HAVING MIN(Location) = MAX(Location) OR MIN(LOCATION) IS NULL;