Not that familiar with SQL.
I have the follow SQL :
UPDATE my_Table
SET num = num + 1
WHERE id = 1
I would like limit that num column that it won't exceed a threshold, assuming 100. If num will reach 100, I would like it to stay 100 and will not increase.
I assume if statement should be included here somehow. but cant figure out how.
I'm seeing answers that would solve your problem from an update statement, all fine whatever way it is done.
Until someone creates a statement that doesn't adhere to your constraint, like a new co-worker, someone sleepy that forgets it or whatever reason. You should probably know about other options to force this rule.
You could create an SQL constraint that checks that num is never set to more than 100. That way any update or insert statement that makes this value more than 100 would result in an error rather than doing the insert or update.
Another way to force this rule "under the hood", not really beginner level, would be to create an update and insert trigger that would check for num being more than 100 and reset it to 100 in that case. That wouldn't result in an error when you run the insert or update statement. I don't have a good link for ANSI-SQL triggers, but each RDBMS has good documentation.
You can use a CASE expression:
UPDATE my_Table
SET num = CASE WHEN num+1 >= 100 THEN 100 ELSE num+1 END
WHERE id=1
try:
UPDATE my_Table SET num=num+1 WHERE id=1 AND num<=99
in that case you can use IIF for shorter version
UPDATE my_Table SET num=(IIF((num+1)>100,num,num+1)) WHERE id=1
Related
I'm looking for a possible solution to the following. I have data stored in a table to keep track of a special increment number the customer wants in the DB. This is a special number they use internally.
What I would like to do is automatically increment this number in the table when I select it. So I don't have the problem of another transaction, from someone else using the system, using the same ID number.
So I want to select the current number and increment it by one at once so I don't have duplicates. How would I go about doing this if it is even possible?
UPDATE the_table
SET the_column = the_column + 1
WHERE qualifier = X
RETURNING the_column;
This ought to do the trick, with the caveat that it will return the new id rather than the old one:
UPDATE foo
SET id=nextval('foo_sequence')
WHERE ...
RETURNING *
(This is a follow-up to the answer by "onedaywhen" on a question I posted earlier today.)
Hi everyone. Say I have a table MyTable with two int fields, PrimaryKey and MyNumber. (And other fields not directly relevant to this question). MyNumber has a unique constraint and a check constraint limiting it to BETWEEN 1 AND n. (Let's say n=5 for now.)
1,2
2,NULL
3,5
4,NULL
5,NULL
6,1
7,NULL
How could an UPDATE be written to change the record where PrimaryKey=2 so that MyNumber has a non-NULL value? I don't care what value it has, so long as it's not a NULL and meets it's two constraints of being unique and within range.
I'm using MS SQL Server, but I'm hoping there's an answer using standard SQL.
(I'm also hoping there won't have to be a table with the numbers 1 to n as contents.)
Many thanks.
WITH CTE AS (
SELECT 1 N
UNION ALL
SELECT N + 1 FROM CTE WHERE N < 5
)
UPDATE MyTable
SET MyNumber = (
SELECT TOP 1 N FROM CTE
WHERE NOT EXISTS (SELECT * FROM MyTable WHERE MyNumber = N)
)
WHERE PrimaryKey = 2
In plain English:
Generate integers between 1 and 5 (WITH CTE AS ...).
Pick the first of these integers that does not already exist in MyNumber (SELECT TOP 1 ...).
Assign that integer to MyNumber, in the row identified by PrimaryKey = 2 (UPDATE ...).
If this query fails to find a suitable value, it will simply set the MyNumber to NULL.
WARNING: This might still viloate UNIQUE constraint on MyNumber in a concurrent environment (i.e. when two concurrently-executing transactions try to run this same query in parallel). So, you'd have to be prepared to retry the query if necessary.
Look up the #ROW_NUMBER function for MS-SQL, I can't off the top of my head think of code right now, and I'm not near my DB server to do some tests, but if memory serves, #ROW_NUMBER in association with a 'IS NOT NULL' check should help you achive your goal.
#ROW_NUMBER documentation : http://msdn.microsoft.com/en-us/library/ms186734.aspx
For other flavours of SQL i can't think of a solution at present.
I can't help but point out that the next version of SQL (code name Denali) will support SEQUENCES, clearly ideal in this case.
The code would look something like this:
CREATE SEQUENCE Count1to5
START WITH 1
INCREMENT BY 1
MAX VALUE 5;
I'm not sure exactly how or if you would be able to skip values on updates using a where and I don't have a test server set up with the beta, but it seems like it is worth mentioning this solution will be available soon.
I want to make a query or some function in Oracle what can update ~24000 rows. For example 1 update query looks like this:
update numbers
set status = 1 and some_id = 123123
where number_id = 1231;
"some_id" and "number_id" are different in every query.
Problem is doing this one by one is taking too much time, I need quicker solution.
Put the varying values into a table and then use that in your query:
update numbers n
set status=1,
some_id = (select some_id from newtable t where t.number_id = n.number_id)
where number_id in (select number_id from newtable);
It looks as if you had hard-wired the predicates and update values in your query. You might be able to improve performance quite a bit by using bind variables. With bind variables, Oracle only needs one hard-parse for all 24k identical SQL UPDATE statements, instead of 24k hard-parses (and update execution plans) for 24k distinct SQL UPDATE statements.
With Java:
update numbers
set status = ?, some_id = ?
where number_id = ?;
With other tools:
update numbers
set status = :1, some_id = :2
where number_id = :3;
Write a PL-SQL stored procedure and pass in the parameters. Call it once and be done.
Or use PreparedStatement and batch your requests.
They probably take too long because you do a round trip for each one. Batch will help a great deal, because you'll only do one round trip.
I'm refactoring the data import procedure for an enterprise application and came across a snippet I'd like to find a better solution. When importing data we have to create a unique entity for each data set and there is a counter in a field to be used to assign this id sequentially. You read the field to get the next free id and increment it afterwards to prepare for the next time.
At the moment this is done in two steps in the original app, written in 'C':
SELECT idnext FROM mytable;
UPDATE mytable SET idnext = idnext + 1;
Obviously there is a race condition here, if multiple processes do the same thing.
Edit: Important corequisite: I can not touch the database/field definition, this rules out a sequence.
We are rewriting in perl, and I'd like to do the same thing, but better. An atomic solution would be nice. Unfortunately my SQL skills are limited, so I'm turning to collective wisdom :-)
In this particular case, a sequence is the right solution as mentioned. But if in some future situation you need to both update something and return a value in the same statement, you can use the RETURNING clause:
UPDATE atable SET foo = do_something_with(foo) RETURNING foo INTO ?
If the calling code is PL/SQL, replace the ? with a local PL/SQL variable; otherwise you can bind it as an output parameter in your program.
Edit: Since you mentioned Perl, something like this ought to work (untested):
my $sth = $dbh->prepare('UPDATE mytable SET idnext = idnext + 1 returning idnext into ?');
my $idnext;
$sth->bind_param_inout(1, \$idnext, 8);
$sth->execute; # now $idnext should contain the value
See DBI.
Why not use a sequence?
Create the sequence one time, using whatever START WITH value you want:
CREATE SEQUENCE mysequence
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
NOCACHE
NOORDER;
Then in your application code at runtime you can use this statement to get the next value:
SELECT mysequence.NEXTVAL
INTO idnext
FROM DUAL;
Update: Using a sequence would be the preferred method, but since you can't change the database then I agree that using RETURNING should work for your situation:
UPDATE mytable
SET idnext = idnext + 1
RETURNING idnext
INTO mylocalvariable;
Use SELECT FOR UPDATE statement. It guarantees mutually exclusive rights to the record :
"SELECT
FOR UPDATE;
A sequence will do the job, have a look at e.g. Oracle sequences
update accounts set type=1 where id=2;
update accounts set type=3 where id=4;
At the same time? If you mean that you want to make sure no other queries affect the table before your queries are done, you're going to want to wrap them in a transaction.
exactly what you ask will be
update accounts set type = case id when 2 then 1 else 3 end where id in (2,4)
but in general this is of course impossibe.
This:
UPDATE ACCOUNTS t SET t.type = 1 WHERE t.id = 2; UPDATE ACCOUNTS t SET t.type = 3 WHERE t.id = 4;
...is acceptable SQL statement syntax - the ";" is a statement delimiter. The statements won't be executed simultaneously - nothing in a database is, everything is queued & processed in order of submission (though fiddling with isolation levels can work around that).
However, most APIs & IDEs prevent multiple statement execution like this in order to stop SQL injection attacks. What are you using that you find is stopping you from executing the statement?
If you want them to occur at once you could use a transaction:
SET autocommit=0;
START TRANSACTION;
update accounts set type=1 where id=2;
update accounts set type=3 where id=4;
COMMIT;
Note that you need to disable auto commit or the commit will occur when the first update occurs.
You may find this article interesting. I got more out of the comments than the article, but the article was interesting:
http://blog.bubble.ro/how-to-make-multiple-updates-using-a-single-query-in-mysql/
His technique probably won't work for you, but it is one approach.
The best bet would be to write a stored procedure and have it do the multiple updates, or, if there is some way for a program to determine the values for the second query, you could use a trigger, but I expect that won't help you.
It's not a generic solution but in this special case:
update accounts
set type = id - 1
where id = 2
or id = 4;
That's one statement...