2009-12-08 4 views
2

Je veux convertir une table stockant des données de paire valeur Nom à la forme relationnelle dans SQL Server 2008.Mise à jour des données non validées à une cellule avec dans une instruction UPDATE

table Source

Strings 
ID Type String 
100 1 John 
100 2 Milton 
101 1 Johny 
101 2 Gaddar 

cible requise

Customers 
ID FirstName LastName 
100 John  Milton 
101 Johny  Gaddar 

Je suis la stratégie donnée ci-dessous,

Peupler la Cus Table tomer avec des valeurs d'identité dans le tableau des chaînes

INSERT INTO CUSTOMERS SELECT DISTINCT ID FROM Strings 

Vous obtenez le

Customers 
ID FirstName LastName 
100 NULL  NULL 
101 NULL  NULL 

Les clients de mise à jour ci-dessous avec le reste des attributs en se joignant à l'aide de chaînes colonne ID. De cette façon, chaque enregistrement dans les clients aura 2 enregistrements correspondants correspondants.

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 

Un état intermédiaire sera 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 

Mais cela ne fonctionne pas comme prévu. Car lors de l'affectation des valeurs dans la clause SET, seules les valeurs validées sont définies à la place des valeurs non validées. Y at-il de toute façon pour définir des valeurs non validées (avec dans le temps de traitement de la requête) dans UPDATE instruction? Je ne suis pas à la recherche de solutions de rechange, mais je fais mon approche en disant à SQL Server d'utiliser des données non validées pour UPDATE.

Répondre

0

Jetez un oeil à cela, il faut éviter toutes les étapes que vous aviez

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, je ne pense pas que vous trouverez une solution à ce que vous recherchez. De UPDATE (Transact-SQL) il déclare

Utilisation de UPDATE avec la clause FROM

Les résultats d'une instruction UPDATE sont undefined si la déclaration comprend une clause FROM non spécifiée dans de telle sorte que seule valeur est disponible pour chaque occurrence de colonne qui est mise à jour, c'est-à-dire si l'instruction UPDATE n'est pas déterministe.Pour exemple, dans l'instruction UPDATE dans le script suivant, les deux lignes dans Table1 répondent aux qualifications de la clause FROM dans l'instruction UPDATE; mais il est indéfini quelle ligne de Le tableau 1 est utilisé pour mettre à jour la ligne dans Tableau2.

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; 
+0

C'est encore la même chose que la réponse 1. Au lieu de faire des mises à jour séparées, vous utilisez plusieurs jointures. Cela provoquera également plusieurs analyses sur la table de chaînes que je veux éviter. Et je ne cherche pas de solutions alternatives, mais fais que mon approche fonctionne en disant à SQL Server d'utiliser des données non validées. Merci quand même. Appréciez l'effort :) – Faiz

+0

Avez-vous jeté un coup d'œil à READUNCOMMITTED hint? –

+0

J'ai essayé de régler le NIVEAU D'ISOLATION juste au-dessus de l'instruction pour READ UNCOMMITTED mais cela ne fait aucune différence (SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;). Je pensais que cela n'aurait aucun effet avec "dans les changements de requête" – Faiz

1

La meilleure façon de le faire serait de diviser la mise à jour en deux:

UPDATE Customers 
SET FirstName = Strings.String 
FROM Customers 
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 1 

Et puis:

UPDATE Customers 
SET LastName = Strings.String 
FROM Customers 
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 2 

Il y a probablement des façons de le faire dans une requête tel qu'un dérivé table, mais à moins que ce soit une exigence spécifique, je voudrais simplement utiliser cette approche.

+0

C'était la méthode que j'ai utilisée précédemment. Je voulais faire un club pour sauver des scans sur la table des cordes car il y avait des millions d'enregistrements. – Faiz

+0

qu'en est-il d'une table dérivée? –

0

Astander est correcte (j'accepte sa réponse). La mise à jour ne se produit pas en raison d'un problème de lecture UNCOMMITTED mais à cause des plusieurs lignes renvoyées par JOIN. J'ai vérifié. UPDATE sélectionne uniquement la première ligne générée à partir des enregistrements multiples pour mettre à jour la table d'origine. C'est le comportement de MSSQL, Sybase et de tels RDMBMS mais Oracle n'autorise pas ce genre de mise à jour et il lance une erreur. J'ai vérifié cette chose pour MSSQL.

De plus, MSSQL ne prend pas en charge la mise à jour d'une cellule avec des données UNCOMMITTED. Je ne connais pas le statut avec d'autres SGBDR. Et je n'ai aucune idée si anyRDBMS fournit avec dans la gestion de niveau de requête ISOLATION.

Une solution alternative sera de le faire en deux étapes, Agréger pour un pivot, puis insérer. Cela a des analyses plus faibles par rapport aux méthodes données dans les réponses ci-dessus.

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 

Merci à mon ami Roji Thomas de m'avoir aidé.

Questions connexes