103

I have a simple table Structure like this:

Table tempData

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

And I also have another table names as tempDataView like this

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

I want to update the table tempDataView , by setting the Marks according to the tempDataView - Name compared with tempData - Name

Yes let me show you what I tried, I tried to solve this using the Cursor and its solved perfectly, but I am finding the way to solve it using the Subquery

Here it is:

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

Actually it's like the homework for me to solve it using the Subquery.

John Woo
  • 258,903
  • 69
  • 498
  • 492
Narendra Pal
  • 6,474
  • 13
  • 49
  • 85

5 Answers5

225

you can join both tables even on UPDATE statements,

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

for faster performance, define an INDEX on column marks on both tables.

using SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )
John Woo
  • 258,903
  • 69
  • 498
  • 492
  • 1
    its right. but please suggest me any way to do this using the subquery. – Narendra Pal Jan 31 '13 at 04:54
  • 1
    updated the answer with `subquery`, but i rather using `JOIN` than `SUBQUERY`. – John Woo Jan 31 '13 at 04:57
  • 1
    Why should one define an `INDEX` on the `marks` columns? Should it not be on the `Name` columns? – lindelof May 08 '15 at 06:34
  • 1
    Got an error : Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. – Pradip Jan 13 '16 at 07:43
  • 2
    Try the subquery on its own and adjust it until you get only 1 result. Probably change `SELECT` to `SELECT TOP 1` – vahanpwns Apr 11 '16 at 00:28
  • No Actually if you want to update multiple you do not want to do Top 1 You want to change '=' to 'IN' – Mark Monforti Jan 02 '18 at 19:43
  • 1
    The join version doesn't work for me, actually. It just takes the value in the first result of the joined table and fills all entries with it, rather than taking a new value for the next entry. – User1291 Jul 15 '19 at 10:56
42

because you are just learning I suggest you practice converting a SELECT joins to UPDATE or DELETE joins. First I suggest you generate a SELECT statement joining these two tables:

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

Then note that we have two table aliases a and b. Using these aliases you can easily generate UPDATE statement to update either table a or b. For table a you have an answer provided by JW. If you want to update b, the statement will be:

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

Now, to convert the statement to a DELETE statement use the same approach. The statement below will delete from a only (leaving b intact) for those records that match by name:

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

You can use the SQL Fiddle created by JW as a playground

cha
  • 10,301
  • 1
  • 18
  • 26
15

Here in my sample I find out the solution of this, because I had the same problem with updates and subquerys:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id
RedBassett
  • 3,469
  • 3
  • 32
  • 56
sfranco
  • 151
  • 1
  • 3
  • 2
    Thank you for this answer! To help others reading this, can you quickly add an explanation as to why this code solves the problem? – RedBassett Feb 12 '20 at 19:11
1

The title of this thread asks how a subquery can be used in an update. Here's an example of that:

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
  • 4,700
  • 3
  • 29
  • 28
  • I'm not sure how this would even compile, there is no group by for the count(*) to know what to count. – crthompson Jul 31 '18 at 21:03
  • @paqogomez just try it - on any table that has any records in it. e,g. **select count(*) from EventLog where year = 2018** – Graham Laight Aug 08 '18 at 15:03
  • So then you are simply counting the entire table. I stand by my down vote, this has nothing to do with the question (regardless of the title) – crthompson Aug 11 '18 at 23:47
  • That's your prerogative, but the title of this thread is "update query using subquery", and my example self-evidently does exactly that. fyi I am not counting "the entire table" - count(*) is followed by a "where" clause - so it is counting rows that meet the "where" condition. – Graham Laight Aug 14 '18 at 15:27
0

Here is a nice explanation of update operation with some examples. Although it is Postgres site, but the SQL queries are valid for the other DBs, too. The following examples are intuitive to understand.

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

However, the second query may give unexpected results if salesmen.id is not a unique key, whereas the first query is guaranteed to raise an error if there are multiple id matches. Also, if there is no match for a particular accounts.sales_id entry, the first query will set the corresponding name fields to NULL, whereas the second query will not update that row at all.

Hence for the given example, the most reliable query is like the following.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);
Memin
  • 3,788
  • 30
  • 31