Thread: creating "job numbers"
I have been working with PG for about 2 months now. I am creating a job tracking system for my company. I have written a front end on the workstations (all macintoshes) that seems to be working quite well. However, I have a problem with a concept. In my current setup I have only one workstation that is actually inputting new jobs. So, I took the expedient way to create the job number. Ask PG to count the rows, add a magic number and insert this data. This all happens in one connection. What are the odds of two people hitting the db at the same time? In the current set up nil. There is only one entry computer. I want to change the system to use a job number generated by PG. I created a test table and I am playing with inserting and the sequence function works great. However, I am at a loss of how to pick up this next (last) job. I have read the docs and I still am confused. I can not first ask with the number will be, and asking for the previous oid after the fact can also lead to the same problem. so that leaves me with, 1 ask for that last oid from this workstation ip, or 2 since a job is inserted with data, I could do a select of this data after the insert (not very elegant). How are you professionals handling this problem? I like the ability to insert and have the system give me the number. As I grow into more workstations inputting the jobs I won't have to worry about chasing the next highest number. Thanks, Ted P.
postgresql <pgsql@symcom.com> wrote: >I can not first ask with the number will be, and asking for the previous >oid after the fact can also lead to the same problem. If you use sequences and the currval() and nextval() functions, you can. See e.g. http://www.postgresql.org/docs/aw_pgsql_book/node85.html . HTH, Ray -- "a infinite number of monkeys typing into GNU emacs would never make a good program".../linux/Documentation/CodingStyle
Check out nextval() and currval(). They do exactly what you need. They're also specific to the current backend, so you can guarantee that the same value won't be passed to two different frontend sessions. nextval('sequencename') -> the number that will be assigned next in the current backend; and currval('sequencename') -> the number that was last assigned in the current backend (undefined ifthere's been no INSERT in this session) Hope this helps. ---------------------------------------------------------------------- Andrew J Perrin - Ph.D. Candidate, UC Berkeley, Dept. of Sociology (Soon: Asst Professor of Sociology, U of North Carolina, Chapel Hill) andrew_perrin@unc.edu - http://www.unc.edu/~aperrin On Thu, 22 Mar 2001, postgresql wrote: > I have been working with PG for about 2 months now. I am creating a > job tracking system for my company. I have written a front end on the > workstations (all macintoshes) that seems to be working quite well. > However, I have a problem with a concept. > > In my current setup I have only one workstation that is actually > inputting new jobs. So, I took the expedient way to create the job > number. Ask PG to count the rows, add a magic number and insert > this data. This all happens in one connection. What are the odds of > two people hitting the db at the same time? In the current set up nil. > There is only one entry computer. I want to change the system to use > a job number generated by PG. I created a test table and I am > playing with inserting and the sequence function works great. > However, I am at a loss of how to pick up this next (last) job. I have > read the docs and I still am confused. I can not first ask with the > number will be, and asking for the previous oid after the fact can > also lead to the same problem. so that leaves me with, 1 ask for > that last oid from this workstation ip, or 2 since a job is inserted with > data, I could do a select of this data after the insert (not very elegant). > > How are you professionals handling this problem? I like the ability to > insert and have the system give me the number. As I grow into more > workstations inputting the jobs I won't have to worry about chasing > the next highest number. > > Thanks, > Ted P. > > > > ---------------------------(end of broadcast)--------------------------- > TIP 4: Don't 'kill -9' the postmaster >
From: "postgresql" <pgsql@symcom.com> > In my current setup I have only one workstation that is actually > inputting new jobs. So, I took the expedient way to create the job > number. Ask PG to count the rows, add a magic number and insert > this data. This all happens in one connection. What are the odds of > two people hitting the db at the same time? In the current set up nil. > There is only one entry computer. I want to change the system to use > a job number generated by PG. I created a test table and I am > playing with inserting and the sequence function works great. > However, I am at a loss of how to pick up this next (last) job. I have > read the docs and I still am confused. I can not first ask with the > number will be, and asking for the previous oid after the fact can > also lead to the same problem. so that leaves me with, 1 ask for > that last oid from this workstation ip, or 2 since a job is inserted with > data, I could do a select of this data after the insert (not very elegant). I wouldn't use oid's for this - create a jobnum field and use a sequence. Sequences are smarter than you think, use: select currval('mysequence') to get the current value and select nextval('mysequence') to get the next value *for this backend* So - each client will be guaranteed a unique number. Note that if you "use up" a number and e.g. an insert fails there will be gaps in your numbering. Also check out the SERIAL data-type which can provide automatic numbering for the fields. I'm sure there are examples in Bruce's book (there's a link on www.postgresql.org) - Richard Huxton
postgresql wrote: > How are you professionals handling this problem? I like the ability to > insert and have the system give me the number. As I grow into more > workstations inputting the jobs I won't have to worry about chasing > the next highest number. Two possible ways: 1. If you can live with gaps in the job numbers, you can use the serial data type. That is, you create your tablelike CREATE TABLE jobs ( job_id serial PRIMARY KEY, employee_id integer REFERENCESstaff, ... ); Now your application can INSERT a row not specifying an explicit value for the job_id like INSERT INTO jobs (employee_id, ...) VALUES (4711, ...); and reading the PostgreSQL assigned job_id back with SELECT currval('jobs_job_id_seq'); Even if there are other processes doing the same concurrently, the assigned job_id is guaranteedto be unique and the currval() given back by your database connection isn't affected by it. 2. If you cannot live with gaps in the numbers, have a separate table containing counters like CREATE TABLE app_counter ( count_name text PRIMARY KEY, count_val integer; ); INSERT INTO app_counter VALUES ('job_id', 0); Now it's the duty of your application to use transactions and do mainly the following: BEGIN TRANSACTION; UPDATE app_counter set count_val = count_val + 1 WHERE count_name ='job_id'; INSERT INTO jobs SELECT count_val, 4711, ... FROM app_counter WHERE count_name ='job_id'; SELECT count_val FROM app_counter WHERE count_name = 'job_id'; COMMIT TRANSACTION; For method 1, transaction aborts can cause missing job_id's because sequence numbers aren't rolled back. OTOH method 2 will lock the table app_counter at the UPDATE and release the lock at COMMIT. So it'll have a little less throughput than method 1, but if you really get a performance problem with creating job's in the database, your companymust be gushing cash and there should be plenty of money for some bigger boxes :-). Jan -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com # _________________________________________________________ Do You Yahoo!? Get your free @yahoo.com address at http://mail.yahoo.com
Jan, Thanks, I must be missing something here. Bear with me, I am trying to form an intelligent question. Using the serial data type... I don't understand when the backend would skip a number. If the db is assigning the number with the insert, then if two (or more) clients are trying to insert into the db at the exact same time, only those that are successful should get a number. I am trying to envision a situation where two clients hit at the same time and because of problem with the insert, one aborts and the serial data number is skipped. I would have assumed that the aborted insert is just skipped no harm done. I guess that I could then break the insert down into two parts. Insert only the client name in order to grab the next job number then update the row. I think I should be able to reduce the number of aborted inserts to 1 in a couple of thousand were the abort is due to client input error. (I wanted to say in a million but that just seemed too far fetched) The only reason that I can think of that would cause an abort would be that data was currupted in transit to the db. Or the front end crashed and sent bad data. Is this reasonable? I feel that people with more expierence might shed a little light here. Thanks for your time. Ted -----Original Message----- From: Jan Wieck <JanWieck@Yahoo.com> To: postgresql <pgsql@symcom.com> Date: Thu, 22 Mar 2001 14:48:19 -0500 (EST) Subject: Re: [SQL] creating "job numbers" > > Two possible ways: > > 1. If you can live with gaps in the job numbers, you can use > the serial data type. That is, you create your table like > > CREATE TABLE jobs ( > job_id serial PRIMARY KEY, > employee_id integer REFERENCES staff, > ... > ); > > Now your application can INSERT a row not specifying an > explicit value for the job_id like > > INSERT INTO jobs (employee_id, ...) > VALUES (4711, ...); > > and reading the PostgreSQL assigned job_id back with > > SELECT currval('jobs_job_id_seq'); > > Even if there are other processes doing the same > concurrently, the assigned job_id is guaranteed to be > unique and the currval() given back by your database > connection isn't affected by it. >
Thanks Micheal, I guess what I am trying to figure out is, 'how important is this in reality, in a working setup'. I know that at times I want things to be perfect, and it is not necessary. I was thinking about how I do this manually. I would take a sheet of paper, write numbers down the left column. make a couple of sheets with increasing numbers. As jobs enter the shop, I populate the meta data. If a job gets killed, it is marked as dead but the number does not go away. It could be used again. What I really need to do is: Insert "blank" into openjobs; SELECT currval('jobs_job_id_seq'); UPDATE openjobs "job meta data" where jobno= "returned number from prev select" Even if this job fails, I have the empty row. I can choose to put a job in there later if I want. Or leave it blank. I feel that all the numbers have to be accounted for as used or null. But it should not skip. Thanks, Ted -----Original Message----- From: Michael Ansley <Michael.Ansley@intec-telecom-systems.com> To: 'postgresql' <pgsql@symcom.com> Date: Fri, 23 Mar 2001 13:22:09 -0000 Subject: RE: [SQL] creating "job numbers" > The procedure is something more like this: > > The first backend grabs the sequence number, say 1, and tries to > insert. > Whether or not this insert succeeds, the number 1 is gone from the > sequence. > Then backend two tries to insert, and grabs the number 2 from the > sequence. > After this, the first backend rolls back, and doesn't insert. The next > backend will get number 3. And so number 1 is lost. If the session is > caching sequence number, then even more numbers may be lost. Anyway, > the > principle is that sequences do not roll back. Once you have a number, > it's > gone, whether or not you use it. This is because keeping track of > numbers > to keep them contiguous is a time-consuming exercise, and causes > locking > problems. So, the principle is that a sequence will always give you a > distinct number, but not necessarily the next number. > > Hope this helps... > > > MikeA
"postgresql" <pgsql@symcom.com> writes: > Using the serial data type... I don't understand when the backend > would skip a number. The value returned by a nextval() call will not be returned again by other nextval() calls, even if the surrounding transaction is later rolled back. Agreed, this isn't in line with full transactional semantics, but it was deemed the more useful thing to do precisely because of that. If you want the other behavior you can build it yourself, whereas there's no way to build the actual behavior of sequence objects in plain SQL. The reason why this is more useful is that with this behavior, acquirers of serial numbers don't need to wait for each other. A no-skipped-numbers implementation requires each would-be acquirer to block waiting to see if previous acquirers commit or not. You get no concurrency at all if you build your system like that. regards, tom lane
postgresql wrote: > Jan, > > Thanks, I must be missing something here. Bear with me, I am > trying to form an intelligent question. > > Using the serial data type... I don't understand when the backend > would skip a number. > If the db is assigning the number with the insert, then if two (or > more) clients are trying to insert into the db at the exact same time, > only those that are successful should get a number. I am trying to > envision a situation where two clients hit at the same time and > because of problem with the insert, one aborts and the serial data > number is skipped. I would have assumed that the aborted insert is > just skipped no harm done. Concurrency will not cause your transactions to abort. It's just if you do BEGIN; INSERT INTO ... ROLLBACK; that the generated sequence numbers don't get rolled back. So you might find job numbers 1, 2, 4 where 3 is missingbecause it's transaction aborted (explicit rollback or error during processing). The serial data type willnever fill in those gaps. Jan -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com # _________________________________________________________ Do You Yahoo!? Get your free @yahoo.com address at http://mail.yahoo.com