it-swarm.com.de

Aktualisieren und Verknüpfen mehrerer Zeilen. Welcher Zeilenwert wird verwendet?

Angenommen, ich habe die folgende Anweisung und der innere Join ergibt 3 Zeilen, wobei a.Id = b.Id ist, aber jede der 3 Zeilen unterschiedliche b.Value-Werte hat. Da nur eine Zeile aus Tabelle A aktualisiert wird, welcher der 3 Werte wird bei der Aktualisierung verwendet?

UPDATE a
SET a.Value = b.Value
FROM tableA AS a
INNER JOIN tableB as b 
ON a.Id = b.Id
22
sooprise

Ich glaube nicht, dass es Regeln für diesen Fall gibt, und Sie können sich nicht auf ein bestimmtes Ergebnis verlassen.

Wenn Sie nach einer bestimmten Zeile suchen, sagen Sie die neueste, dann können Sie apply verwenden, wie zum Beispiel:

UPDATE  a
SET     a.Value = b.Value
FROM    tableA AS a
CROSS APPLY
        (
        select  top 1 *
        from    tableB as b
        where   b.id = a.id
        order by
                DateColumn desc
        ) as b
17
Andomar

In der Regel wird in diesem Szenario die erste Zeile in der Reihenfolge des physischen Index für die Tabelle angezeigt. In der Praxis sollten Sie dies als nicht deterministisch behandeln und etwas einschließen, das Ihr Ergebnis auf eine Zeile einschränkt.

7
JamieSee

In meinem Fall ist die beste Option zum Aktualisieren mehrerer Datensätze die Verwendung der Zusammenführungsabfrage (unterstützt von SQL Server 2008). In dieser Abfrage haben Sie die vollständige Kontrolle über die Aktualisierung. Sie können die Ausgabeabfrage auch zur weiteren Verarbeitung verwenden.

Beispiel: Ohne Ausgabeklausel (nur Aktualisierung)

;WITH cteB AS
( SELECT Id, Col1, Col2, Col3  
  FROM B WHERE Id > 10  ---- Select Multiple records
)
MERGE A
USING cteB
ON(A.Id = cteB.Id) -- Update condition
WHEN MATCHED THEN UPDATE
SET  
A.Col1 = cteB.Col1,  --Note: Update condition i.e; A.Id = cteB.Id cant appear here   again.
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3;

Beispiel: Mit OputPut-Klausel

CREATE TABLE #TempOutPutTable
  {
  PkId INT NOT NULL,
  Col1 VARCHAR(50),
  Col2 VARCHAR(50)
  }

;WITH cteB AS
( SELECT Id, Col1, Col2, Col3
FROM B WHERE Id > 10
)
MERGE A
USING cteB
ON(A.Id = cteB.Id)
WHEN MATCHED THEN UPDATE
SET  
A.Col1 = cteB.Col1, 
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3
OUTPUT 
 INSERTED.Id, cteB.Col1, A.Col2 INTO #TempOutPutTable;

--Do what ever you want with the data in temporary table
SELECT * FROM #TempOutPutTable; -- you can check here which records are updated.
2
sudhAnsu63

Folgendes habe ich mir mit SQL Server 2008 ausgedacht

--drop table #b
--drop table #a
select 1 as id, 2 as value
into #a

select 1 as id, 5 as value
into #b

insert into #b
select 1, 3

insert into #b
select 1, 6

select * from #a
select * from #b

UPDATE #a 
SET #a.Value = #b.Value
FROM #a
INNER JOIN #b 
ON #a.Id = #b.Id

Anscheinend wird jedes Mal der oberste Wert einer Basisauswahl verwendet (Zeile 1 von select * from #b). Es kommt also möglicherweise auf die Indizierung an. Ich würde mich jedoch nicht auf die von SQL festgelegte Implementierung verlassen, da diese die Möglichkeit einer Änderung bietet. Stattdessen würde ich vorschlagen, die von Andomar vorgestellte Lösung zu verwenden, um sicherzustellen, dass Sie wissen, welchen Wert Sie wählen werden.

Kurz gesagt, vertraue nicht der Standardimplementierung, erstelle deine eigene. Aber das war eine interessante akademische Frage :)

2
Justin Pihony

Ja, ich habe ein ähnliches Experiment wie Justin Pihony entwickelt:

    IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test ;
SELECT 
1 AS Name, 0 AS value 
INTO #test

IF OBJECT_ID('tempdb..#compare') IS NOT NULL DROP TABLE #compare ;
SELECT 1 AS name, 1 AS value
INTO #compare
INSERT INTO #compare
SELECT 1 AS name, 0 AS value;

SELECT * FROM #test
SELECT * FROM #compare

UPDATE t
SET t.value = c.value
FROM #test t
INNER JOIN #compare c
    ON t.Name = c.name

Nimmt die oberste Zeile in der Vergleichstabelle rechts ein. Sie können die Werte von # compare.value auf 0 und 1 umkehren und erhalten die Umkehrung. Ich stimme den obigen Postern zu ... es ist sehr seltsam, dass diese Operation keine Fehlermeldung auslöst, da sie vollständig verborgen sekundäre Werte ignoriert

0
E.Gannon