57

I have a table 'answers' with an indexed 'problem_id' integer column, a 'times_chosen' integer column, and an 'option' column that's a varchar. Currently the only values for the 'option' column are 'A', 'B', 'C' and 'D', though those may expand later on. I want to increment by one the 'times_chosen' values of many (50-100) answers, when I know the problem_id and option of each of them.

So I need a query that's something like:

UPDATE answers
SET times_chosen = times_chosen + 1
WHERE (problem_id, option) IN ((4509, 'B'), (622, 'C'), (1066, 'D'), (4059, 'A'), (4740, 'A')...)

Is this possible?

Edit to add: Turns out that it is, using the exact syntax that I invented!

5
  • 2
    It should, at least I think it would in MySQL and MSSQL. Have you tried it? You can test it with SET times_chosen = times_chosen Commented Jul 13, 2011 at 0:05
  • Oh wow, it actually does work, just as I wrote it! It even uses the index! Thanks Dirk - if you just copy your response below as an answer I'll be happy to accept it. Commented Jul 13, 2011 at 0:20
  • heh, I didn't know that was valid syntax. That's handy =D Commented Jul 13, 2011 at 0:27
  • 3
    @PreciousBodilyFluids May you please add a line of confirmation in your question that it works like a charm ^^ Commented Apr 7, 2017 at 3:27
  • The question contains the best answer in it. Commented Jul 3, 2024 at 10:41

5 Answers 5

43

You can join against a virtual table of sorts:

SELECT * FROM answers
JOIN (VALUES (4509, 'B'), (622, 'C'), (1066, 'D'), (4059, 'A'), (4740, 'A')) 
    AS t (p,o)
ON p = problem_id AND o = option

You can do something similar with UPDATE.

Sign up to request clarification or add additional context in comments.

3 Comments

Apart from being cooler, is there a reason why this solution is much more up-voted that @Dirk's solution?
This works well for postgresql. I need the corresponding query for spring jpa. Can you help ?
this is more flexible, we can change the operator on a per-column basis.
23

It should, at least I've done it before in other SQLs.

Have you tried it? You can test it with SET times_chosen = times_chosen

1 Comment

It actually works. Question itself is solution to asked problem. Yet it is not mentioned in the question nor in the answer enough. I've spent some time trying other solutions for delete query until I found out in PostgreSQL docs that this should work too and solves my problem :-)
5

You can do this if you cast the data to an array first:

UPDATE answers
SET times_chosen = times_chosen + 1
WHERE ARRAY[problem_id::VARCHAR,option] IN ('{4509,B}', '{622,C}', ... )

However, this will be incredibly inefficient, as it cannot use indexes. Using a JOIN as suggested by @Frank Farmer is a far better solution:

UPDATE answers a
SET times_chosen = times_chosen + 1
FROM (VALUES (4509,'B'), (622,'C') ...) AS x (id,o)
    WHERE x.id=a.problem_id AND x.o=a.option;

Comments

0

Another option is to use Common Table Expressions (i.e. WITH) which can be combined with the FROM clause for the UPDATE:

CREATE TABLE test (prefix text, alias text, val int);

WITH dataset(prefix, alias) as (
    VALUES ('a', 'b')
        , ('-', '-')
)

UPDATE test t SET val = 2
FROM dataset as f
WHERE t.prefix = f.prefix 
    AND t.alias = f.alias;

Fiddle

Which allows to separate the query logic and manipulated data into separate pieces which can make query more readable/maintainable in some cases.

Comments

-5

You're probably looking for the

SELECT * FROM foo, bar WHERE foo.bob = "NaN" AND bar.alice = "Kentucky";

style syntax. Essentially, you use tablename.rowname to specify what individual field you're looking for. In order to line everything up properly, you add WHERE clauses that make sure the primary keys match:

...WHERE foo.primarykey = bar.primarykey

or similar. You'd do well to look up inner joins.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.