2011-10-24 21 views
7

Tengo una tabla que permite decir que tiene llamada FavoriteFruitsNAME, FRUIT, y GUID para las columnas. La tabla ya está poblada con nombres y frutas. Lo que permite decir:T-SQL para actualizar filas con mismo valor en una columna

NAME  FRUIT  GUID 
John  Apple  NULL 
John  Orange  NULL 
John  Grapes  NULL 
Peter  Canteloupe NULL 
Peter  Grapefruit NULL 

Ok, ahora quiero actualizar la columna GUID con un nuevo GUID (usando NEWID()), pero quiero tener la misma GUID por nombre distinto. Así que quiero que todos los John Smiths tengan el mismo GUID, y quiero que el Peters tenga el mismo GUID, pero que el GUID sea diferente al utilizado para los Johns. Por lo que ahora se vería algo como esto:

NAME  FRUIT  GUID 
John  Apple  f6172268-78b7-4c2b-8cd7-7a5ca20f6a01 
John  Orange  f6172268-78b7-4c2b-8cd7-7a5ca20f6a01 
John  Grapes  f6172268-78b7-4c2b-8cd7-7a5ca20f6a01 
Peter  Canteloupe e3b1851c-1927-491a-803e-6b3bce9bf223 
Peter  Grapefruit e3b1851c-1927-491a-803e-6b3bce9bf223 

¿Puedo hacer eso en una instrucción de actualización sin tener que utilizar un cursor? Si es así, ¿puedes dar un ejemplo?

Gracias chicos ...

Respuesta

6

Actualizar un CTE no funcionarán porque it'll evaluate per row. Una variable de tabla funcionaría:

Debería poder usar una variable de tabla como fuente desde la cual actualizar los datos. Esto no se ha probado, pero que se verá algo como:

DECLARE @n TABLE (Name varchar(10), Guid uniqueidentifier); 

INSERT @n 
SELECT Name, newid() AS Guid 
FROM FavoriteFruits 
GROUP BY Name; 

UPDATE f 
    SET f.Guid = n.Guid 
FROM @n n 
    JOIN FavoriteFruits f ON f.Name = n.Name 

Así que puebla una variable con un GUID por nombre, luego se une de nuevo a la mesa de originales y actualizaciones en consecuencia.

+1

"CTE no funcionará porque evaluará por fila": lo mismo se aplica a otras expresiones de tabla, p. la cláusula 'USING' en una declaración' MERGE'. Usar 'MERGE' con una variable de tabla en lugar de una expresión de tabla funcionará, por supuesto. – onedaywhen

+0

Gracias por agregar ese enlace. Había oído hablar del tema, pero no me había dado cuenta de que habían decidido cerrar esto como 'no arreglarán'. La semántica me parece incorrecta (ciertamente no es lo que esperaba). – GilM

+0

Gracias Matt, trabajó como un campeón. – Ryan

0

Para aclarar los comentarios, se trata de una expresión de tabla en la cláusula USING de una declaración MERGE.

El siguiente no funcionará porque it'll evaluate per row:

MERGE INTO FavoriteFruits 
    USING (
      SELECT NAME, NEWID() AS GUID 
      FROM FavoriteFruits 
      GROUP 
       BY NAME 
     ) AS source 
     ON source.NAME = FavoriteFruits.NAME 
WHEN MATCHED THEN 
    UPDATE 
     SET GUID = source.GUID; 

Pero lo siguiente, usando una variable de tabla, funcionará:

DECLARE @n TABLE 
(
NAME VARCHAR(10) NOT NULL UNIQUE, 
GUID UNIQUEIDENTIFIER NOT NULL UNIQUE 
); 

INSERT INTO @n (NAME, GUID) 
    SELECT NAME, NEWID() 
    FROM FavoriteFruits 
    GROUP 
     BY NAME; 

MERGE INTO FavoriteFruits 
    USING @n AS source 
     ON source.NAME = FavoriteFruits.NAME 
WHEN MATCHED THEN 
    UPDATE 
     SET GUID = source.GUID; 
0

Hay una solución de un único estado también, que, sin embargo, tiene algunas limitaciones La idea es utilizar OPENQUERY(), así:

UPDATE FavoriteFruits 
SET GUID = n.GUID 
FROM (
    SELECT NAME, GUID 
    FROM OPENQUERY(
    linkedserver, 
    'SELECT NAME, NEWID() AS GUID FROM database.schema.FavoriteFruits GROUP BY NAME' 
) 
) n 
WHERE FavoriteFruits.NAME = n.NAME 

Esta solución implica que es necesario crear un servidor vinculado auto-apuntando. Otra especificidad es que no puede usar este método en variables de tablas ni tablas temporales locales (las globales funcionarían tan bien como las tablas "normales").

Cuestiones relacionadas