视图上的TSQL外键?

我有一个SQL-Server 2008数据库和一个使用外键约束来强制引用完整性的模式。 按预期工作。 现在,用户在原始表上创建视图,仅处理数据的子集。 我的问题是过滤某些表中的某些数据集而不是其他表将会违反外键约束。
想象两张桌子“一”和“两”。 “one”只包含一个值为1,2,3的id列。 “两个”引用“一个”。 现在你在两个表上创建视图。 表“two”的视图不会过滤任何内容,而表“one”的视图会除去第一个视图中的所有行。 第二个视图中的条目最终会指向任何地方。

有什么办法可以避免这种情况? 你可以在视图之间有外键约束吗?

针对部分意见作出一些澄清
我知道,即使在通过视图插入时,底层约束也能确保数据的完整性。 我的问题在于消耗观点的陈述。 这些陈述是在原始表格的基础上编写的,并假设某些连接不会失败。 这个假设在使用表格时始终有效 - 但视图可能会破坏它。
由于大量的引用表,在创建视图时首先加入/检查所有约束是annyoing。 因此我希望避免这种情况。


彼得已经打了这个,但最好的解决方案是:

  • 创建一次“主”逻辑(即过滤引用的表)。
  • 让相关表的所有视图都加入为(1)创建的视图,而不是原始表。
  • 也就是说,

    CREATE VIEW v1 AS SELECT * FROM table1 WHERE blah
    
    CREATE VIEW v2 AS SELECT * FROM table2 WHERE EXISTS
      (SELECT NULL FROM v1 WHERE v1.id = table2.FKtoTable1)
    

    当然,用于在一个表上传播过滤器以查看下属表的语法糖会很方便,但是,它并不是SQL标准的一部分。 也就是说,这个解决方案仍然足够好 - 高效,简单,可维护,并且保证消费代码所需的状态。


    我爱你的问题。 它尖叫着熟悉查询优化器,以及它如何看到某些连接是多余的,如果它们没有任何用途,或者它可以简化知道连接另一侧最多有一次连接的事情。

    所以,最大的问题在于是否可以针对索引视图的CIX创建FK。 答案是否定的。

    create table dbo.testtable (id int identity(1,1) primary key, val int not null);
    go
    create view dbo.testview with schemabinding as
    select id, val
    from dbo.testtable
    where val >= 50
    ;
    go
    insert dbo.testtable
    select 20 union all
    select 30 union all
    select 40 union all
    select 50 union all
    select 60 union all
    select 70 
    go
    create unique clustered index ixV on dbo.testview(id);
    go
    create table dbo.secondtable (id int references dbo.testview(id));
    go
    

    除了最后一条语句之外,所有这些工作都是有效的

    Msg 1768, Level 16, State 0, Line 1
    Foreign key 'FK__secondtable__id__6A325CF7' references object 'dbo.testview' which is not a user table.
    

    所以外键必须引用一个用户表。

    但是......下一个问题是关于是否可以引用在SQL 2008中过滤的唯一索引,以实现类似于视图的FK。

    答案仍然是否定的。

    create unique index ixUV on dbo.testtable(val) where val >= 50;
    go
    

    这成功了。

    但是现在如果我尝试创建一个引用val列的表

    create table dbo.thirdtable (id int identity(1,1) primary key, val int not null check (val >= 50) references dbo.testtable(val));
    

    (我希望与筛选索引中的筛选匹配的检查约束可能有助于系统理解FK应该保留)

    但我得到一个错误说:

    There are no primary or candidate keys in the referenced table 'dbo.testtable' that matching the referencing column list in the foreign key 'FK__thirdtable__val__0EA330E9'.
    

    如果我删除已过滤的索引并创建一个未过滤的唯一非聚集索引,那么我可以创建dbo.thirdtable而不会有任何问题。

    所以恐怕答案似乎还是没有。


    我花了一些时间来弄清楚这里的误会 - 不知道我是否还完全理解,但在这里。 我会用一个例子,接近你的,但有一些数据 - 这些条款让我更容易思考。

    所以前两个表; A =部门B =员工

    CREATE TABLE Department
      ( 
       DepartmentID int PRIMARY KEY
      ,DepartmentName varchar(20)
      ,DepartmentColor varchar(10)
      )
    GO 
    CREATE TABLE Employee
      ( 
       EmployeeID int PRIMARY KEY
      ,EmployeeName varchar(20)
      ,DepartmentID int FOREIGN KEY REFERENCES Department ( DepartmentID )
      )
    GO 
    

    现在我会把一些数据扔进去

    INSERT  INTO Department
      ( DepartmentID, DepartmentName, DepartmentColor )
     SELECT 1, 'Accounting', 'RED' UNION
     SELECT 2, 'Engineering', 'BLUE' UNION
     SELECT 3, 'Sales', 'YELLOW'  UNION
     SELECT 4, 'Marketing', 'GREEN' ;
    
    INSERT  INTO Employee
      ( EmployeeID, EmployeeName, DepartmentID )
     SELECT 1, 'Lyne', 1 UNION
     SELECT 2, 'Damir', 2 UNION
     SELECT 3, 'Sandy', 2 UNION
     SELECT 4, 'Steve', 3 UNION
     SELECT 5, 'Brian', 3 UNION
     SELECT 6, 'Susan', 3 UNION
        SELECT 7, 'Joe', 4 ;
    

    所以,现在我将在第一张桌子上创建一个视图来过滤一些部门。

    CREATE VIEW dbo.BlueDepartments
    AS
    SELECT * FROM dbo.Department
    WHERE DepartmentColor = 'BLUE'
    GO
    

    这返回

    DepartmentID DepartmentName       DepartmentColor
    ------------ -------------------- ---------------
    2            Engineering          BLUE
    

    并根据您的示例,我将为第二个表添加视图,该表不会过滤任何内容。

    CREATE VIEW dbo.AllEmployees
    AS
    SELECT * FROM dbo.Employee
    GO
    

    这返回

    EmployeeID  EmployeeName         DepartmentID
    ----------- -------------------- ------------
    1           Lyne                 1
    2           Damir                2
    3           Sandy                2
    4           Steve                3
    5           Brian                3
    6           Susan                3
    7           Joe                  4
    

    在我看来,你认为雇员5号,DepartmentID = 3点没有任何意义?

    “你会在第二个视图中看到没有任何意义的条目。”

    那么,它指向DepartmentDepartmentID = 3 ,用外键指定。 即使您尝试在视图上加入视图,也不会有任何问题:

    SELECT  e.EmployeeID
           ,e.EmployeeName
           ,d.DepartmentID
           ,d.DepartmentName
           ,d.DepartmentColor
    FROM    dbo.AllEmployees AS e
            JOIN dbo.BlueDepartments AS d ON d.DepartmentID = e.DepartmentID
            ORDER BY e.EmployeeID
    

    返回

    EmployeeID  EmployeeName         DepartmentID DepartmentName       DepartmentColor
    ----------- -------------------- ------------ -------------------- ---------------
    2           Damir                2            Engineering          BLUE
    3           Sandy                2            Engineering          BLUE   
    

    因此,这里没有任何东西被破坏,连接根本没有找到DepartmentID <> 2匹配记录。这实际上与我连接表格然后在第一个视图中包含过滤器一样:

    SELECT  e.EmployeeID
           ,e.EmployeeName
           ,d.DepartmentID
           ,d.DepartmentName
           ,d.DepartmentColor
    FROM    dbo.Employee AS e
            JOIN dbo.Department AS d ON d.DepartmentID = e.DepartmentID
            WHERE d.DepartmentColor = 'BLUE'
         ORDER BY e.EmployeeID
    

    再次返回:

    EmployeeID  EmployeeName         DepartmentID DepartmentName       DepartmentColor
    ----------- -------------------- ------------ -------------------- ---------------
    2           Damir                2            Engineering          BLUE
    3           Sandy                2            Engineering          BLUE
    

    在这两种情况下,联接都不会失败,他们只是按预期做到的。

    现在我将尝试通过视图打破参照完整性(没有DepartmentID = 127)

    INSERT  INTO dbo.AllEmployees
          ( EmployeeID, EmployeeName, DepartmentID )
    VALUES( 10, 'Bob', 127 )
    

    这导致:

    Msg 547, Level 16, State 0, Line 1
    The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Employee__Depart__0519C6AF". The conflict occurred in database "Tinker_2", table "dbo.Department", column 'DepartmentID'.
    

    如果我试图通过视图删除部门

    DELETE FROM dbo.BlueDepartments
    WHERE DepartmentID = 2
    

    其结果是:

    Msg 547, Level 16, State 0, Line 1
    The DELETE statement conflicted with the REFERENCE constraint "FK__Employee__Depart__0519C6AF". The conflict occurred in database "Tinker_2", table "dbo.Employee", column 'DepartmentID'.
    

    所以对基础表的限制仍然适用。

    希望这会有所帮助,但也许我误解了你的问题。

    链接地址: http://www.djcxy.com/p/65883.html

    上一篇: TSQL foreign keys on views?

    下一篇: SQL conflicted with the FOREIGN KEY constraint