PostgreSQL assign sequence number from SELECT - sql

I want to restart sequence with max+1 of certain table.
SELECT max(id)+1
INTO testVal
FROM project;
ALTER SEQUENCE project_id_seq RESTART testVal;
This gives syntax error at testVal. Can someone please explain me what is a problem, propose alternative solution?

for sequences you should be using setval
SELECT SETVAL('project_id_seq', (SELECT max(id)+1 FROM project))
https://www.postgresql.org/docs/current/functions-sequence.html

Related

Limit a value in SQL

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

derby Syntax error: Encountered EOF Next Value sequence

Working with embedded database derby version 10.12.1.1.
I have created a sequence successfully as below
CREATE SEQUENCE BUCKET_SEQ AS BIGINT START WITH 1000;
But when trying to get next value using
SELECT NEXT VALUE FOR BUCKET_SEQ
below error encountered:
Syntax error: Encountered "<EOF>" at line 1, column 40.
Please suggest any pointers.
You have to SELECT from something, and the something has to be some sort of a table.
The simplest thing to do is to use the SQL VALUES keyword, which makes an (unnamed, temporary) table for you.
You then give the table a name, and the table's column a name, and select the value from that:
select t from ( values next value for bucket_seq ) s( t);
T
--------------------
1000
There are other syntax forms possible, but this is a simple one that you can use.

Using CTE with while loop in SQL server 2005

I want to use CTE with while loop. Is it possible
my code:
; with myCTE(a,b)
(
select .,. from abc
)
while exist (select * from mycet) -- causing issue
Please suggest some solution.
Regards,
Anuprita
No, the documentation states:
A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE
statement that references some or all the CTE columns.
But you should use a set based approach instead of loops anyway. Apart from that, it is not clear what your query should return.

How to retrieve the current value of an oracle sequence without increment it?

Is there an SQL instruction to retrieve the value of a sequence that does not increment it.
Thanks.
EDIT AND CONCLUSION
As stated by Justin Cave It's not useful to try to "save" sequence number so
select a_seq.nextval from dual;
is good enough to check a sequence value.
I still keep Ollie answer as the good one because it answered the initial question. but ask yourself about the necessity of not modifying the sequence if you ever want to do it.
SELECT last_number
FROM all_sequences
WHERE sequence_owner = '<sequence owner>'
AND sequence_name = '<sequence_name>';
You can get a variety of sequence metadata from user_sequences, all_sequences and dba_sequences.
These views work across sessions.
EDIT:
If the sequence is in your default schema then:
SELECT last_number
FROM user_sequences
WHERE sequence_name = '<sequence_name>';
If you want all the metadata then:
SELECT *
FROM user_sequences
WHERE sequence_name = '<sequence_name>';
EDIT2:
A long winded way of doing it more reliably if your cache size is not 1 would be:
SELECT increment_by I
FROM user_sequences
WHERE sequence_name = 'SEQ';
I
-------
1
SELECT seq.nextval S
FROM dual;
S
-------
1234
-- Set the sequence to decrement by
-- the same as its original increment
ALTER SEQUENCE seq
INCREMENT BY -1;
Sequence altered.
SELECT seq.nextval S
FROM dual;
S
-------
1233
-- Reset the sequence to its original increment
ALTER SEQUENCE seq
INCREMENT BY 1;
Sequence altered.
Just beware that if others are using the sequence during this time - they (or you) may get
ORA-08004: sequence SEQ.NEXTVAL goes below the sequences MINVALUE and cannot be instantiated
Also, you might want to set the cache to NOCACHE prior to the resetting and then back to its original value afterwards to make sure you've not cached a lot of values.
select MY_SEQ_NAME.currval from DUAL;
Keep in mind that it only works if you ran select MY_SEQ_NAME.nextval from DUAL; in the current sessions.
The follows is often used:
select field_SQ.nextval from dual; -- it will increase the value by 1 for each run
select field_SQ.currval from DUAL;
However the following is able to change the sequence to what you expected. The 1 can be an integer (negative or positive)
alter sequence field_SQ increment by 1 minvalue 0
This is not an answer, really and I would have entered it as a comment had the question not been locked. This answers the question:
Why would you want it?
Assume you have a table with the sequence as the primary key and the sequence is generated by an insert trigger. If you wanted to have the sequence available for subsequent updates to the record, you need to have a way to extract that value.
In order to make sure you get the right one, you might want to wrap the INSERT and RonK's query in a transaction.
RonK's Query:
select MY_SEQ_NAME.currval from DUAL;
In the above scenario, RonK's caveat does not apply since the insert and update would happen in the same session.
I also tried to use CURRVAL, in my case to find out if some process inserted new rows to some table with that sequence as Primary Key. My assumption was that CURRVAL would be the fastest method. But a) CurrVal does not work, it will just get the old value because you are in another Oracle session, until you do a NEXTVAL in your own session. And b) a select max(PK) from TheTable is also very fast, probably because a PK is always indexed. Or select count(*) from TheTable. I am still experimenting, but both SELECTs seem fast.
I don't mind a gap in a sequence, but in my case I was thinking of polling a lot, and I would hate the idea of very large gaps. Especially if a simple SELECT would be just as fast.
Conclusion:
CURRVAL is pretty useless, as it does not detect NEXTVAL from another session, it only returns what you already knew from your previous NEXTVAL
SELECT MAX(...) FROM ... is a good solution, simple and fast, assuming your sequence is linked to that table
If your use case is that some backend code inserts a record, then the same code wants to retrieve the last insert id, without counting on any underlying data access library preset function to do this, then, as mentioned by others, you should just craft your SQL query using SEQ_MY_NAME.NEXTVAL for the column you want (usually the primary key), then just run statement SELECT SEQ_MY_NAME.CURRVAL FROM dual from the backend.
Remember, CURRVAL is only callable if NEXTVAL has been priorly invoked, which is all naturally done in the strategy above...
My original reply was factually incorrect and I'm glad it was removed. The code below will work under the following conditions a) you know that nobody else modified the sequence b) the sequence was modified by your session. In my case, I encountered a similar issue where I was calling a procedure which modified a value and I'm confident the assumption is true.
SELECT mysequence.CURRVAL INTO v_myvariable FROM DUAL;
Sadly, if you didn't modify the sequence in your session, I believe others are correct in stating that the NEXTVAL is the only way to go.

Oracle SQL: How to read-and-increment a field

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