Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update a column based on other values in the row

Tags:

mysql

Consider the following trials table:

CREATE TABLE trials
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name_A VARCHAR(6),
name_B VARCHAR(6),
score_A INT,
score_B INT);

Abstractly, this represents a series of trials in which two possible things, A and B, are tried. A and B each get a score.

Later we add two columns winner and loser, both of the same datatype as name_A and name_B:

ALTER TABLE trials
ADD COLUMN winner VARCHAR(6),
ADD COLUMN loser VARCHAR(6);

For each trial, we want to fill in winner with whichever name corresponds to the higher score.

For example, if a trial has

╔════════╦════════╦═════════╦═════════╗
║ name_A ║ name_B ║ score_A ║ score_B ║
╠════════╬════════╬═════════╬═════════╣
║ alice  ║ bob    ║ 10      ║ 5       ║
╚════════╩════════╩═════════╩═════════╝

then for that trial winner should be alice. Similarly, in this case loser should be populated with bob:

╔════════╦════════╦═════════╦═════════╦════════╦═══════╗
║ name_A ║ name_B ║ score_A ║ score_B ║ winner ║ loser ║
╠════════╬════════╬═════════╬═════════╬════════╬═══════╣
║ alice  ║ bob    ║ 10      ║ 5       ║ alice  ║ bob   ║
╚════════╩════════╩═════════╩═════════╩════════╩═══════╝

How does one UPDATE to set the winner and loser columns in the trials table properly?


Attempt:

I considered doing this with a sub-query. Here is a sub-query which find both the winners and losers:

SELECT id, name_A AS winner, name_B AS loser
  FROM trials
  WHERE score_A > score_B
  UNION
  SELECT id, name_B AS winner, name_A AS loser
  FROM trials
  WHERE score_B > score_A)

Trying to just get the winners, I did this:

UPDATE trials SET winner=(
  SELECT id, winner from (  
    SELECT id, name_A AS winner
      FROM trials
      WHERE score_A > score_B
    UNION
    SELECT id, name_B AS winner
      FROM trials
      WHERE score_B > score_A) AS temp
  )
  WHERE temp.id = trials.id;

but it does not work because the field temp.id is not recognized.

like image 651
DanielSank Avatar asked Aug 15 '15 23:08

DanielSank


People also ask

How do you update a column based on another column?

In such a case, you can use the following UPDATE statement syntax to update column from one table, based on value of another table. UPDATE first_table, second_table SET first_table. column1 = second_table. column2 WHERE first_table.id = second_table.

How do you update a table based on values from another table?

In this article, we will see, how to update from one table to another table based on ID match. We can update the table using UPDATE statement in SQL. The update statement is always followed by the SET command. The SET command is used to specify which columns and values need to be updated in a table.

Can you modify the rows in a table based on values from another table?

You can update an entire row in one table with values from a row in another table.


2 Answers

You could make it without a subquery:

Query:

UPDATE test.trials AS t
SET t.winner=CASE WHEN t.score_A > t.score_B THEN t.name_A
                  WHEN t.score_A < t.score_B THEN t.name_B
             ELSE NULL END,
    t.loser=CASE WHEN t.score_A > t.score_B THEN t.name_B
                  WHEN t.score_A < t.score_B THEN t.name_A
             ELSE NULL END;

Test:

Create table:

CREATE TABLE trials
    (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name_A VARCHAR(6),
    name_B VARCHAR(6),
    score_A INT,
    score_B INT);

Empty table:

SELECT * FROM test.trials;

Test data:

INSERT INTO test.trials (id, name_A, name_B, score_A, score_B) VALUES ('1', 'alice', 'bob', '10', '5');
INSERT INTO test.trials (id, name_A, name_B, score_A, score_B) VALUES ('2', 'onare', 'some', '5', '11');

SELECT * FROM test.trials;

+----+--------+--------+---------+---------+
| id | name_A | name_B | score_A | score_B |
+----+--------+--------+---------+---------+
|  1 | alice  | bob    |      10 |       5 |
|  2 | onare  | some   |       5 |      11 |
+----+--------+--------+---------+---------+

Adding winner and loser columns:

ALTER TABLE test.trials 
    ADD COLUMN winner VARCHAR(10) NULL COMMENT '' AFTER score_B,
    ADD COLUMN loser VARCHAR(10) NULL COMMENT '' AFTER winner;

SELECT * FROM test.trials;

+----+--------+--------+---------+---------+--------+-------+
| id | name_A | name_B | score_A | score_B | winner | loser |
+----+--------+--------+---------+---------+--------+-------+
|  1 | alice  | bob    |      10 |       5 | NULL   | NULL  |
|  2 | onare  | some   |       5 |      11 | NULL   | NULL  |
+----+--------+--------+---------+---------+--------+-------+

Running the query:

UPDATE test.trials AS t
    SET t.winner=CASE WHEN t.score_A > t.score_B THEN t.name_A
    WHEN t.score_A < t.score_B THEN t.name_B
    ELSE NULL END,
    t.loser=CASE WHEN t.score_A > t.score_B THEN t.name_B
    WHEN t.score_A < t.score_B THEN t.name_A
    ELSE NULL END;


SELECT * FROM test.trials;

+----+--------+--------+---------+---------+--------+-------+
| id | name_A | name_B | score_A | score_B | winner | loser |
+----+--------+--------+---------+---------+--------+-------+
|  1 | alice  | bob    |      10 |       5 | alice  | bob   |
|  2 | onare  | some   |       5 |      11 | some   | onare |
+----+--------+--------+---------+---------+--------+-------+

You could make it even using IF on winner and loser. I used CASE because if there's a match between score_A and score_B, what do you want the query to do?. Add a new column match.

like image 196
oNare Avatar answered Nov 09 '22 10:11

oNare


UPDATE Trials
SET Winner =
    CASE
        WHEN score_A > score_B THEN name_A
        WHEN score_B > score_A THEN name_B
        ELSE NULL
        END
like image 42
Zach Allen Avatar answered Nov 09 '22 10:11

Zach Allen