Actualizar la consulta usando Subconsulta en Sql Server

83

Tengo una estructura de tabla simple como esta:

Tabla tempData

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║    80 ║
║ Ravi     ║    85 ║
║ Sanjay   ║    90 ║
╚══════════╩═══════╝

Y también tengo otros nombres de tablas como tempDataView como este

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Ravi     ║       ║
║ Ravi     ║       ║
║ Sanjay   ║       ║
╚══════════╩═══════╝

Quiero actualizar la tabla tempDataView , estableciendo las Marcas de acuerdo con tempDataView - Nombre en comparación con tempData - Nombre

Sí, déjame mostrarte lo que intenté, intenté resolver esto usando el Cursor y se resolvió perfectamente, pero estoy encontrando la manera de resolverlo usando la Subconsulta

Aquí está:

Declare @name varchar(50),@marks varchar(50)
Declare @cursorInsert CURSOR
set @cursorInsert = CURSOR FOR
Select name,marks from tempData
OPEN @cursorInsert
FETCH NEXT FROM @cursorInsert
into @name,@marks
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE tempDataView set marks = @marks where name = @name
FETCH NEXT FROM @cursorInsert
INTO @name,@marks
END
CLOSE @cursorInsert
DEALLOCATE @cursorInsert

En realidad, es como una tarea para mí resolverlo usando la Subconsulta.

Narendra Pal
fuente

Respuestas:

180

puede unir ambas tablas incluso en UPDATEdeclaraciones,

UPDATE  a
SET     a.marks = b.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

para un rendimiento más rápido, defina una INDEXcolumna markson en ambas tablas.

utilizando SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )
John Woo
fuente
1
es lo correcto. pero sugiéreme alguna forma de hacerlo usando la subconsulta.
Narendra Pal
1
actualicé la respuesta con subquery, pero prefiero usar JOINque SUBQUERY.
John Woo
1
¿Por qué debería uno definir una INDEXen las markscolumnas? ¿No debería estar en las Namecolumnas?
lindelof
1
Obtuve un error: la subconsulta devolvió más de 1 valor. Esto no está permitido cuando la subconsulta sigue =,! =, <, <=,>,> = O cuando la subconsulta se usa como expresión.
Pradip
1
Pruebe la subconsulta por sí sola y ajústela hasta que obtenga solo 1 resultado. Probablemente cambie SELECTaSELECT TOP 1
vahanpwns
33

debido a que está aprendiendo, le sugiero que practique la conversión de uniones SELECT en UPDATE o DELETE joins. Primero le sugiero que genere una declaración SELECT uniendo estas dos tablas:

SELECT *
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Luego observe que tenemos dos alias de tabla ay b. Con estos alias, puede generar fácilmente una instrucción UPDATE para actualizar la tabla a o b. Para la tabla a, tiene una respuesta proporcionada por JW. Si desea actualizar b, la declaración será:

UPDATE  b
SET     b.marks = a.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Ahora, para convertir la declaración en una declaración DELETE, use el mismo enfoque. La siguiente declaración se eliminará asolo de (dejando b intacto) para aquellos registros que coincidan por nombre:

DELETE a
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Puede usar el SQL Fiddle creado por JW como un patio de recreo

cha
fuente
5
es la forma correcta de aprender. +1 por mostrar el camino a estudiar.Gracias
Narendra Pal
3

Aquí, en mi muestra, descubro la solución de esto, porque tuve el mismo problema con las actualizaciones y subquerías:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id
sfranco
fuente
1
¡Gracias por esta respuesta! Para ayudar a otros a leer esto, ¿puede agregar rápidamente una explicación de por qué este código resuelve el problema?
RedBassett
0

El título de este hilo pregunta cómo se puede utilizar una subconsulta en una actualización. He aquí un ejemplo de eso:

update [dbName].[dbo].[MyTable] 
set MyColumn = 1 
where 
    (
        select count(*) 
        from [dbName].[dbo].[MyTable] mt2 
        where
            mt2.ID > [dbName].[dbo].[MyTable].ID
            and mt2.Category = [dbName].[dbo].[MyTable].Category
    ) > 0
Graham Laight
fuente
No estoy seguro de cómo se compilaría esto, no hay un grupo por el recuento (*) para saber qué contar.
crthompson
@paqogomez simplemente pruébalo, en cualquier tabla que tenga registros. p.ej. seleccione recuento (*) de EventLog donde año = 2018
Graham Laight
Entonces, simplemente está contando toda la tabla.
Apoyo
Esa es su prerrogativa, pero el título de este hilo es "actualización de consulta usando subconsulta", y mi ejemplo evidentemente hace exactamente eso. Para su información, no estoy contando "toda la tabla"; el recuento (*) va seguido de una cláusula "dónde", por lo que se cuentan las filas que cumplen la condición "dónde".
Graham Laight
0

Aquí hay una buena explicación de la operación de actualización con algunos ejemplos. Aunque es un sitio de Postgres, las consultas SQL también son válidas para las otras bases de datos. Los siguientes ejemplos son intuitivos de comprender.

-- Update contact names in an accounts table to match the currently assigned salesmen:

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

-- A similar result could be accomplished with a join:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

Sin embargo, la segunda consulta puede dar resultados inesperados si salesmen.id no es una clave única, mientras que se garantiza que la primera consulta generará un error si hay múltiples coincidencias de id. Además, si no hay ninguna coincidencia para una entrada de accounts.sales_id en particular, la primera consulta establecerá los campos de nombre correspondientes en NULL, mientras que la segunda consulta no actualizará esa fila en absoluto.

Por lo tanto, para el ejemplo dado, la consulta más confiable es la siguiente.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);
Memin
fuente
Desafortunadamente, el primer formulario no funciona en el servidor MS SQL.
AntoineL