<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. SQL
  3. Creating and changing data
All lessons in this course

Lesson 9 of 54 16 minBeginner

Changing and removing rows: UPDATE and DELETE

Change values with UPDATE and remove rows with DELETE, always with a WHERE clause. Preview with SELECT, use a transaction as a safety net, and see what foreign keys protect.

UPDATE changes values in existing rows. SET says which columns get which new values, and WHERE says which rows. The WHERE clause is exactly the one you know from SELECT:

Query.sql
UPDATE dbo.ProductsSET Price = 19.99, Stock = Stock + 10WHERE ProductId = 1; SELECT @@ROWCOUNT AS RowsUpdated; SELECT ProductId, Name, Price, Stock FROM dbo.Products WHERE ProductId = 1;
Output
RowsUpdated
-----------
          1

ProductId  Name         Price  Stock
---------  -----------  -----  -----
        1  Claw hammer  19.99     50

Stock = Stock + 10 reads the old value and writes a new one. Every expression in SET sees the row as it was before the update, so the order of the assignments does not matter. @@ROWCOUNT tells you how many rows the last statement touched; read it straight away, because the next statement replaces it.

Interactive

UPDATE and DELETE, safely

Preview.sql
SELECT ProductId, Name, CategoryId, Price, Stock, UnitFROM dbo.ProductsWHERE CategoryId = 1;
ProductIdNameCategoryIdPriceStockUnit
11Claw hammer118.5040each
22Cordless drill189.0012each
33Tape measure 8 m19.7565each
Step 1: the SELECT shows the 3 rows the change will touch. Same FROM and WHERE, so what you see is exactly what will change.

The missing WHERE

Without WHERE, UPDATE and DELETE affect every row in the table. It is the most expensive typo in SQL, and SSMS has no undo button. Three habits protect you:

  1. Write the SELECT first. Write SELECT * FROM dbo.Products WHERE …, check the rows, then change only the first line into UPDATE … SET … or DELETE.
  2. Check the row count. SSMS prints “(n rows affected)”. If you expected 3 and it says 12, stop.
  3. Use a transaction when the change matters, so you can look before you commit.

A transaction as a safety net

BEGIN TRANSACTION starts a unit of work. Nothing is final until COMMIT; ROLLBACK undoes everything since BEGIN. Here a price rise is checked, found to be wrong, and undone:

Query.sql
BEGIN TRANSACTION; UPDATE dbo.Products SET Price = Price * 1.10;   -- oops: no WHERE SELECT TOP (3) Name, Price FROM dbo.Products ORDER BY ProductId; ROLLBACK;   -- undo it SELECT TOP (3) Name, Price FROM dbo.Products ORDER BY ProductId;
Output
Name              Price
----------------  -----
Claw hammer       20.35
Cordless drill    97.90
Tape measure 8 m  10.73

Name              Price
----------------  -----
Claw hammer       18.50
Cordless drill    89.00
Tape measure 8 m   9.75

OUTPUT: old and new values

In an UPDATE, OUTPUT can return each row’s value before (deleted.) and after (inserted.) the change, a built-in audit of what you did:

Query.sql
UPDATE dbo.ProductsSET Price = Price * 1.10OUTPUT inserted.ProductId, deleted.Price AS OldPrice, inserted.Price AS NewPriceWHERE CategoryId = 1;
Output
ProductId  OldPrice  NewPrice
---------  --------  --------
        1     18.50     20.35
        2     89.00     97.90
        3      9.75     10.73

The new prices are rounded to two decimals as they are stored in the decimal(10,2) column: 9.75 × 1.10 = 10.725 becomes 10.73.

DELETE

DELETE FROM table WHERE … removes whole rows. Ella (customer 5) has never placed an order, so she can be removed:

Query.sql
DELETE FROM dbo.CustomersWHERE CustomerId = 5; SELECT @@ROWCOUNT AS RowsDeleted;
Output
RowsDeleted
-----------
          1

Asha (customer 1) has orders. Her orders point at her through a foreign key, and SQL Server will not leave them pointing at a customer who no longer exists:

Query.sql
DELETE FROM dbo.CustomersWHERE CustomerId = 1;
Output
Msg 547, Level 16, State 0, Line 1
The DELETE statement conflicted with the REFERENCE constraint "FK__Orders__Customer__3E52440B". The conflict occurred in database "BuildMart", table "dbo.Orders", column 'CustomerId'.

The strange constraint name was made up by SQL Server, because the setup script did not name the foreign key; on your server the hex digits at the end will differ. Foreign keys are a safety net for DELETE in the same way that types are a safety net for INSERT. The Constraints lesson shows how to choose what happens instead (for example, deleting the orders too).

DELETE or TRUNCATE?

`DELETE FROM t``TRUNCATE TABLE t`
Removesthe rows matching WHERE (all if none)every row; no WHERE allowed
Speed on big tablesslow: logs every rowfast: frees whole pages
IDENTITY counterkeeps countingresets to the seed
Table referenced by a foreign keyallowed if no rows are referencednot allowed at all
Triggers (Programmability module)firedo not fire
Quick check

After UPDATE dbo.Products SET Stock = 0 WHERE Unit = N'tin'; what does SELECT @@ROWCOUNT; return?

Quick check

In SET Price = Price * 2, Stock = Price, which Price does Stock get?

Practice

Orders that have been Pending since before 1 June 2024 are to be cancelled. Update their Status to Cancelled, report how many rows changed, then list every order’s id, date and status.

Show a hint

Two conditions in WHERE: Status = 'Pending' AND OrderDate < '2024-06-01'. Read @@ROWCOUNT straight after the UPDATE.

Show the solution
Solution.sql
UPDATE dbo.OrdersSET Status = 'Cancelled'WHERE Status = 'Pending' AND OrderDate < '2024-06-01'; SELECT @@ROWCOUNT AS RowsUpdated; SELECT OrderId, OrderDate, Status FROM dbo.Orders;
Output
RowsUpdated
-----------
          1

OrderId  OrderDate   Status
-------  ----------  ---------
      1  2024-02-03  Shipped
      2  2024-02-10  Shipped
      3  2024-03-01  Shipped
      4  2024-03-15  Shipped
      5  2024-04-02  Shipped
      6  2024-04-20  Cancelled
      7  2024-05-05  Shipped
      8  2024-05-18  Cancelled
      9  2024-06-01  Pending
     10  2024-06-12  Shipped

Remember

  • UPDATE t SET col = expr, … WHERE … changes values; every SET expression sees the old row.
  • DELETE FROM t WHERE … removes rows; without WHERE, both statements hit every row.
  • Preview with SELECT, check the row count, and wrap important changes in BEGIN TRANSACTION … COMMIT / ROLLBACK.
  • OUTPUT deleted.x, inserted.x shows values before and after.
  • Foreign keys stop deletes that would leave rows pointing at nothing; TRUNCATE is all-or-nothing and resets IDENTITY.
0 of 54 lessons completed