TSQL foreign keys on views?

后端 未结 11 1056
臣服心动
臣服心动 2021-01-01 13:51

I have a SQL-Server 2008 database and a schema which uses foreign key constraints to enforce referential integrity. Works as intended. Now the user creates views on the orig

11条回答
  •  粉色の甜心
    2021-01-01 14:30

    It took me some time to figure out the misunderstaning here -- not sure if I still understand completely, but here it is. I will use an example, close to yours, but with some data -- easier for me to think in these terms.

    So first two tables; A = Department B = Employee

    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 
    

    Now I'll toss some data in

    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 ;
    

    So, now I'll create a view on the first table to filter some departments out.

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

    This returns

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

    And per your example, I'll add a view for the second table which does not filter anything.

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

    This returns

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

    It seems to me that you think that Employee No 5, DepartmentID = 3 points to nowhere?

    "You'll end up with entries in the second view that point nowhere."

    Well, it points to the Department table DepartmentID = 3, as specified with the foreign key. Even if you try to join view on view nothing is broken:

    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
    

    Returns

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

    So nothing is broken here, the join simply did not find matching records for DepartmentID <> 2 This is actually the same as if I join tables and then include filter as in the first view:

    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
    

    Returns again:

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

    In both cases joins do not fail, they simply do as expected.

    Now I will try to break the referential integrity through a view (there is no DepartmentID= 127)

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

    And this results in:

    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'.
    

    If I try to delete a department through the view

    DELETE FROM dbo.BlueDepartments
    WHERE DepartmentID = 2
    

    Which results in:

    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'.
    

    So constraints on underlying tables still apply.

    Hope this helps, but then maybe I misunderstood your problem.

提交回复
热议问题