L'aggiornamento dei dati a revoca per una cella con in un'istruzione UPDATE
-
18-09-2019 - |
Domanda
voglio convertire una tabella di memorizzazione dei dati in coppia nome-valore in forma relazionale in SQL Server 2008.
Tabella di origine
Strings
ID Type String
100 1 John
100 2 Milton
101 1 Johny
101 2 Gaddar
target richiesto
Customers
ID FirstName LastName
100 John Milton
101 Johny Gaddar
sto seguendo la strategia indicato di seguito,
Popolare la tabella Clienti con i valori di ID in stringhe tabella
INSERT INTO CUSTOMERS SELECT DISTINCT ID FROM Strings
Si ottiene il seguente
Customers
ID FirstName LastName
100 NULL NULL
101 NULL NULL
Aggiornamento I clienti con il resto degli attributi unendo a stringhe con colonna ID. In questo modo ogni record di clienti avranno corrispondente 2 record corrispondenti.
UPDATE Customers
SET FirstName = (CASE WHEN S.Type=1 THEN S.String ELSE FirstName)
LastName = (CASE WHEN S.Type=2 THEN S.String ELSE LastName)
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID
uno stato intermedio sarà llike,
ID FirstName LastName ID Type String
100 John NULL 100 1 John
100 NULL Milton 100 2 Milton
101 Johny NULL 101 1 Johny
101 NULL Gaddar 101 2 Gaddar
Ma questo non funziona come previsto. Perché quando l'assegnazione dei valori nella clausola SET
è impostare solo i valori impegnati al posto del non impegnati. Esiste un modo per impostare i valori non impegnati (con nel tempo di elaborazione delle query) nella dichiarazione UPDATE
?
PS: Non sono alla ricerca di soluzioni alternative, ma faccio il mio lavoro approccio dicendo SQL Server per utilizzare i dati non impegnati per UPDATE
Soluzione
Date un'occhiata a questo, si dovrebbe evitare tutti i passaggi che hai avuto
DECLARE @Table TABLE(
ID INT,
Type INT,
String VARCHAR(50)
)
INSERT INTO @Table (ID,[Type],String) SELECT 100 ,1 ,'John'
INSERT INTO @Table (ID,[Type],String) SELECT 100 ,2 ,'Milton'
INSERT INTO @Table (ID,[Type],String) SELECT 101 ,1 ,'Johny'
INSERT INTO @Table (ID,[Type],String) SELECT 101 ,2 ,'Gaddar'
SELECT IDs.ID,
tName.String NAME,
tSur.String Surname
FROM (
SELECT DISTINCT ID
FROM @Table
) IDs LEFT JOIN
@Table tName ON IDs.ID = tName.ID AND tName.[Type] = 1 LEFT JOIN
@Table tSur ON IDs.ID = tSur.ID AND tSur.[Type] = 2
OK, non credo che troverete una soluzione a quello che stai cercando. Da UPDATE (Transact-SQL) afferma
Utilizzo di UPDATE con la clausola FROM
I risultati di un'istruzione UPDATE sono non definito se l'istruzione include una Clausola FROM che non specificato nel modo tale che solo un valore sia disponibili per ogni occorrenza colonna che viene aggiornato, vale a dire se l'aggiornamento dichiarazione non è deterministico. Per esempio, nell'istruzione UPDATE in il seguente script, entrambe le righe in Table1 soddisfare le qualifiche del Clausola FROM nell'istruzione UPDATE; ma non è definito quale riga di Tabella 1 viene utilizzato per aggiornare la riga in Table2.
USE AdventureWorks;
GO
IF OBJECT_ID ('dbo.Table1', 'U') IS NOT NULL
DROP TABLE dbo.Table1;
GO
IF OBJECT_ID ('dbo.Table2', 'U') IS NOT NULL
DROP TABLE dbo.Table2;
GO
CREATE TABLE dbo.Table1
(ColA int NOT NULL, ColB decimal(10,3) NOT NULL);
GO
CREATE TABLE dbo.Table2
(ColA int PRIMARY KEY NOT NULL, ColB decimal(10,3) NOT NULL);
GO
INSERT INTO dbo.Table1 VALUES(1, 10.0), (1, 20.0), (1, 0.0);
GO
UPDATE dbo.Table2
SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB
FROM dbo.Table2
INNER JOIN dbo.Table1
ON (dbo.Table2.ColA = dbo.Table1.ColA);
GO
SELECT ColA, ColB
FROM dbo.Table2;
Altri suggerimenti
Il modo più semplice per farlo sarebbe quello di dividere l'aggiornamento in due:
UPDATE Customers
SET FirstName = Strings.String
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 1
E poi:
UPDATE Customers
SET LastName = Strings.String
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 2
Ci sono probabilmente modi per farlo in una query come ad esempio una tabella derivata, ma a meno che questo è un requisito specifico mi basta usare questo approccio.
Astander è corretta (sto accettando la sua risposta). L'aggiornamento non avviene a causa di un problema di UNCOMMITTED leggere, ma a causa dei molteplici righe restituite dalla JOIN. Ho verificato questo. UPDATE rileva solo la prima riga generato dai più record per aggiornare la tabella originale. Questo è il comportamento per MSSQL, Sybase e tali RDMBMSs ma Oracle non consente questo tipo di un aggiornamento di un d esso genera un errore. Ho verificato questa cosa per MSSQL.
E ancora MSSQL non supporta l'aggiornamento di una cella con i dati commit. Non conoscere lo stato con altri RDBMS. E non ho idea se anyRDBMS offre nella gestione livello di isolamento query.
Una soluzione alternativa sarà farlo in due fasi, aggregato di UNPIVOT e quindi inserire. Questo ha scansioni minori rispetto ai metodi indicati nella risposte di cui sopra.
INSERT INTO Customers
SELECT
ID
,MAX(CASE WHEN Type = 1 THEN String ELSE NULL END) AS FirstName
,MAX(CASE WHEN Type = 2 THEN String ELSE NULL END) AS LastName
FROM Strings
GROUP BY ID
Grazie al mio amico Roji Thomas per avermi aiutato con questo.