none
View not updatable - Warum ? RRS feed

  • Frage

  • Hallo,

    ich habe mir eine View auf dem SQL-Server 2005 gebastelt. Diese besteht aus 2 Tabellen welche per Inner Join gejoint sind.

    Leider kann ich immer nur eine Tabelle innerhalb der View updaten, da ansonsten die bekannt Meldung 'View or function 'View1' is not updatable because the modification affects multiple base tables' auftaucht.

    Bei bisherigen Views hatte ich nie das Problem, daher ist mir nicht klar, woher das kommt bzw. warum das zu Stande kommt ? Und was sind für den Server 'Base Tables' ?

     

    Lösung ist laut Recherche ein INSTEAD OF-Trigger, wobei ich mich damit irgendwie nicht so anfreunden kann.

    Donnerstag, 30. Juni 2011 08:01

Antworten

  • Du vermischt hier zwei Dinge.

    Aber das ist nicht der Fall.

    Mein Beispiel ist zur Demonstration des Begriffs Basistabelle.

    Tabelle A 1-1 Tabelle B. Das ist alles.

    Also:

    USE tempdb ;
    GO
    
    CREATE TABLE A
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          Payload NVARCHAR(255) NOT NULL
        ) ;
    
    CREATE TABLE B
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          idA INT NOT NULL ,
          Payload NVARCHAR(255) NOT NULL ,
          CONSTRAINT FK_B_idA FOREIGN KEY ( idA ) REFERENCES A ( id )
        ) ;
    GO
    
    CREATE VIEW AB
    AS
        SELECT  A.ID AS AID ,
                A.Payload AS APayload ,
                B.ID AS BID ,
                B.Payload AS BPayload
        FROM    A
                INNER JOIN B ON A.ID = B.idA ;
    GO
    
    INSERT  INTO A
    VALUES  ( 'A1' ) ;
    
    INSERT  INTO B
    VALUES  ( 1, 'B1' ) ;
    GO
    
    -- Geht.
    UPDATE  AB
    SET     APayload = APayload + '1' ;
    GO
    
    -- Geht.
    UPDATE  AB
    SET     BPayload = BPayload + '2' ;
    GO
    
    -- Geht nicht.
    UPDATE  AB
    SET     APayload = APayload + '3' ,
            BPayload = BPayload + '3' ;
    GO
    
    SELECT  *
    FROM    AB ;
    GO
    
    DROP VIEW AB ;
    DROP TABLE B ;
    DROP TABLE A ;
    GO

    Bei anderen Views hatte ich das Problem bisher nie, darum frage ich mich, was hier den Unterschied ausmacht, welcher das Updaten verhindert.

    Die Tatsache das eine UPDATE-Anweisung nur Werte in genau einer (Basis-)Tabelle ändern kann/darf.


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 30. Juni 2011 10:15
    Moderator
  • Hallo,

    OR-Mapper können auch nur SQL produzieren.
    Und wenn zwei Tabellen (=> im ORM Klasse) über ein Fremdschlüsselbeziehung verknüpft sind,
    so kann er dafür die benötigten zwei UPDATE-Anweisungen erzeugen und sie in einer Transaktion kapseln.

    Verwendest Du dort eine Sicht, so hast Du das gleiche Problem.

    Gruß Elmar

    Freitag, 1. Juli 2011 09:41
    Beantworter
  • Autsch, noch 'ne Komplexitätsebene mehr? Nein, mit LINQ hat das erstmal nix zu tun. Eventuell ist dein verwendeter OR-Mapper in der Lage aus einem UPDATE zwei zu machen, aber dazu braucht es eben auch diese Information, welche Tabellen den betroffen sind.

    Es stellt sich aber die Frage, warum du, wenn du eh einen OR-Mapper hast, nicht DML-Stored-Procedures arbeitest.

    Somit lautet die Antwort: Keine Ahnung, einfach mal testen. Und vorher mal schauen, ob du die Basistabelleninformation auf Spaltenebene definieren kannst.


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 30. Juni 2011 10:43
    Moderator

Alle Antworten

  • Siehe Aktualisierbare Sichten. Du kannst nur eine Basistabelle per DML aktualisieren. Ansonsten brauchst du zwingend einen INSTEAD OF-Trigger.


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 30. Juni 2011 09:06
    Moderator
  • Das ist mir klar.

    Worüber ich stolpere ist der Begriff 'Basistabelle' - WIe ist diese definiert ?

    Donnerstag, 30. Juni 2011 09:24
  • Na ja, in folgenden Beispiel wird mit einer UPDATE-Anweisung eine Änderung in zwei Basistabellen notwendig:

    USE tempdb ;
    GO
    
    CREATE TABLE A
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          Payload NVARCHAR(255) NOT NULL
        ) ;
    
    CREATE TABLE B
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          idA INT NOT NULL ,
          Payload NVARCHAR(255) NOT NULL ,
          CONSTRAINT FK_B_idA FOREIGN KEY ( idA ) REFERENCES A ( id )
        ) ;
    
    CREATE TABLE C
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          idA INT NOT NULL ,
          Payload NVARCHAR(255) NOT NULL ,
          CONSTRAINT FK_C_idA FOREIGN KEY ( idA ) REFERENCES A ( id )
        ) ;
    GO
    
    CREATE VIEW BC
    AS
        SELECT  B.idA ,
                B.ID AS BID ,
                B.Payload AS BPayload ,
                C.ID AS CID ,
                C.Payload AS CPayload
        FROM    B
                INNER JOIN C ON B.idA = C.idA ;
    GO
    
    CREATE VIEW AB
    AS
        SELECT  A.ID AS AID ,
                A.Payload AS APayload ,
                BC.BID ,
                BC.BPayload
        FROM    A
                INNER JOIN BC ON A.ID = BC.idA ;
    GO
    
    INSERT  INTO A
    VALUES  ( 'A1' ) ;
    
    INSERT  INTO B
    VALUES  ( 1, 'B1' ) ;
    
    INSERT  INTO C
    VALUES  ( 1, 'C1' ) ;
    GO
    
    UPDATE  AB
    SET     APayload = APayload + '!' ,
            BPayload = BPayload + '!' ;
    GO
    
    DROP VIEW AB ;
    DROP VIEW BC ;
    DROP TABLE C ;
    DROP TABLE B ;
    DROP TABLE A ;
    GO

    Das einzige was noch in diesem Begriff steckt ist eigentlich einfach: Stell dir vor du änderst eine Sicht, welche selber aus Sichten besteht. Basistabelle meint die tatsächlich zugrunde liegenden Tabellen.


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 30. Juni 2011 09:36
    Moderator
  • Aber das ist nicht der Fall. Ich habe folgenden Aufbau:

    Tabelle A 1-1 Tabelle B. Das ist alles.

    Bei anderen Views hatte ich das Problem bisher nie, darum frage ich mich, was hier den Unterschied ausmacht, welcher das Updaten verhindert.

    Donnerstag, 30. Juni 2011 10:08
  • Du vermischt hier zwei Dinge.

    Aber das ist nicht der Fall.

    Mein Beispiel ist zur Demonstration des Begriffs Basistabelle.

    Tabelle A 1-1 Tabelle B. Das ist alles.

    Also:

    USE tempdb ;
    GO
    
    CREATE TABLE A
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          Payload NVARCHAR(255) NOT NULL
        ) ;
    
    CREATE TABLE B
        (
          ID INT IDENTITY
                 PRIMARY KEY ,
          idA INT NOT NULL ,
          Payload NVARCHAR(255) NOT NULL ,
          CONSTRAINT FK_B_idA FOREIGN KEY ( idA ) REFERENCES A ( id )
        ) ;
    GO
    
    CREATE VIEW AB
    AS
        SELECT  A.ID AS AID ,
                A.Payload AS APayload ,
                B.ID AS BID ,
                B.Payload AS BPayload
        FROM    A
                INNER JOIN B ON A.ID = B.idA ;
    GO
    
    INSERT  INTO A
    VALUES  ( 'A1' ) ;
    
    INSERT  INTO B
    VALUES  ( 1, 'B1' ) ;
    GO
    
    -- Geht.
    UPDATE  AB
    SET     APayload = APayload + '1' ;
    GO
    
    -- Geht.
    UPDATE  AB
    SET     BPayload = BPayload + '2' ;
    GO
    
    -- Geht nicht.
    UPDATE  AB
    SET     APayload = APayload + '3' ,
            BPayload = BPayload + '3' ;
    GO
    
    SELECT  *
    FROM    AB ;
    GO
    
    DROP VIEW AB ;
    DROP TABLE B ;
    DROP TABLE A ;
    GO

    Bei anderen Views hatte ich das Problem bisher nie, darum frage ich mich, was hier den Unterschied ausmacht, welcher das Updaten verhindert.

    Die Tatsache das eine UPDATE-Anweisung nur Werte in genau einer (Basis-)Tabelle ändern kann/darf.


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 30. Juni 2011 10:15
    Moderator
  • Okay, nun ist es klar.

    Wäre es jedoch möglich die Daten in beiden Tabellen zu ändern, wenn diese über ein LINQ-Statement gejoint sind ? Oder taucht dort dann dieses Problem wieder auf ?

    Donnerstag, 30. Juni 2011 10:21
  • Autsch, noch 'ne Komplexitätsebene mehr? Nein, mit LINQ hat das erstmal nix zu tun. Eventuell ist dein verwendeter OR-Mapper in der Lage aus einem UPDATE zwei zu machen, aber dazu braucht es eben auch diese Information, welche Tabellen den betroffen sind.

    Es stellt sich aber die Frage, warum du, wenn du eh einen OR-Mapper hast, nicht DML-Stored-Procedures arbeitest.

    Somit lautet die Antwort: Keine Ahnung, einfach mal testen. Und vorher mal schauen, ob du die Basistabelleninformation auf Spaltenebene definieren kannst.


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 30. Juni 2011 10:43
    Moderator
  • Hallo,

    OR-Mapper können auch nur SQL produzieren.
    Und wenn zwei Tabellen (=> im ORM Klasse) über ein Fremdschlüsselbeziehung verknüpft sind,
    so kann er dafür die benötigten zwei UPDATE-Anweisungen erzeugen und sie in einer Transaktion kapseln.

    Verwendest Du dort eine Sicht, so hast Du das gleiche Problem.

    Gruß Elmar

    Freitag, 1. Juli 2011 09:41
    Beantworter