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

.
È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top