progress openedge table auto increment? - progress-4gl

I have a table in progress db. (read: NOT POSTGRES).
it has three columns, and I would like one of the column to be auto increment begins at 1 and increment by 1.
Tried the following syntax but it does not see to be working.
create sequence pub.Customer_sequence
start with 1,
increment by 1,
nocycle;
the error message says:
Unable to understand after "Customer_sequence"
could not understand line 2

Progress is not SQL. Some small amount of SQL-89 is included but it is not generally considered useful.
There is nothing in Progress equivalent to an auto-increment field. To get that functionality you might use a combination of CREATE trigger and a SEQUENCE.
You can find an example of a create trigger that uses a sequence in $DLC/sports/crcust.p:
TRIGGER PROCEDURE FOR Create OF Customer.
/* Automatically Increment Customer Number using Next-Cust-Num Sequence */
ASSIGN Customer.Cust-Num = NEXT-VALUE(Next-Cust-Num).

A sequence is perhaps the closest you will get.
Look in the Data Dictionary. You will find it under the Tools menu.
There you have the "Sequence Editor" in the Schema Menu. That might be a good place to start.

Related

Loop through database ANYLOGIC

In my model I want to loop through the database which contains multiple columns (see example) by an event. The idea behind it is that I want to create dynamic events based on the rows in the database.
But I've no clue how to iterate through a database in anylogic and also was not able to find an example of a loop with a database.
The dummycode of my problem would look something like this:
For order in orderdatabase:
Create order based on (order.name, order.quantity, order.arrivaltime, order.deliverylocation)
Where order in the loop is every row of the database, and the value on which the creation is based based on the different column values of that specific row.
Can somebody give me a simple example of how to create such a loop for this specific problem.
Thanks in advance.
Use the database query wizard:
put your cursor into a code field
this will allow you to open the database wizard
select what you need (in your case, you want the "iterate over returned rows and do something" option
Click ok
adjust the dummy code to make it do what you want
For details and examples, check the example models and the AnyLogic help, explaining all options in detail.

How to reset an auto-incremented value when another value changes?

I'm actually working on a PostgreSQL DB structure and I'm having hard time figuring out how to solve a problem.
The DB will be recording data regarding architectural objects.
The main table, "object",have attributes that describe the object with information like type, localization, etc.
One of these attributes is a serial named object_num.
Another table is called "code" which contains a code made of three letters corresponding to the town where the mission is conducted.
Example :
I'm working on an architectural inventory for the city of Paris. The code_name will be PRS and the first entry (aka the first architectural entity : house, bridge, etc) will be associated to object_num 001.
So PRS001 will be a unique identifier referring to this specific architectural entity.
Things going on, I might end up with quite a few entries, for example entry PRS745.
Say this mission isn't finished yet but a new one starts for the city of Bordeaux, where BDX is going to identify the inventory. It would be great that the identifier for the first entry will be BDX001 rather than BDX746 (auto-increment).
Considering this, it will be also nice that, going back to the Paris mission after a few records for the Bordeaux mission (say BDX211), the next value will start back at (PRS)745 rather than (BDX)211.
So, is it possible to reset the value of a serial to 1 when using a new code ?
And is it possible to start back serial increment from the last value of a specific code ?
I guess you can perform this task with constraints and checks, but I'm not really familiar with these and am a bit lost...
Thanks for your help,
Yrkoutsk
You could create separate sequences for each code_name and grab your auo-increment based on the code_name:
CREATE SEQUENCE PRS START 1;
CREATE SEQUENCE BDX START 1;
insert into your_table (object_num, code_name, other_data)
values ( code_name||lpad(nextval(code_name)::char,3,'0')
, code_name, other_data);
You will have to create a new sequence every time you add a new code_name otherwise the db will end up throwing an error when you try accessing the nonexistent sequence.

Postgres count(*) optimization idea

I'm currently working on a project involving keeping track of users and their actions with my database (PostgreSQL as the RDMS), and I have run into an issue when trying to perform COUNT(*) on occurrences of each user. What I want is to be able to, efficiently, count the number of times each user appears from every record, and also be able to achieve looking at counts on a particular date range.
So, the problem is how do we achieve counting the total number of times a user appears from the tables contents, and how do we count the total number on a date range.
What I've tried
As you might know, Postgres doesn't support COUNT(*) very well using indices, so we have to consider other ways to reduce the # of records it looks at in order to speed up the query. So my first approach is to create a table to keep track of the number of times a user has a log message associated with them, and on what day (similar to the idea behind a materialized view, but I dont want continually refresh the materialized view with my count query). Here is what I've come up with:
CREATE TABLE users_counts(user varchar(65536), counter int default 0, day date);
CREATE RULE inc_user_date_count
AS ON INSERT TO main_table
DO ALSO UPDATE users_counts SET counter = counter + 1
WHERE user = NEW.user AND day = DATE(NEW.date_);
What this does is every time a new record is inserted into my 'main_table', we update the current users_counts table to increment the records whose date is equal to the new records date, and the user names are the same.
NOTE: the date_ column in 'main_table' is a timestamp so I must cast the new records date_ to be a DATE type.
The problem is, what if the user column value doesn't already exist in my new table 'users_count' for the current day, then nothing is updated.
Here is my question:
How do I write the rule such that we check if a user exists for the current day, if so increment that counter, otherwise insert new row with user, day, and counter of 1;
I also would like to know if my approach makes sense to do, or is there any ideas I am missing that I just haven't thought about. As my database grows, it is increasingly inefficient to perform counting, so I want to avoid any performance bottlenecks.
EDIT 1: I was able to actually figure this out by creating a separate RULE but I'm not sure if this is correct:
CREATE RULE test_insert AS ON INSERT TO main_table
DO ALSO INSERT INTO users_counts(user, counter, day)
SELECT NEW.user, 1, DATE(NEW.date)
WHERE NOT EXISTS (SELECT user FROM users.log_messages WHERE user = NEW.user_);
Basically, an insert happens if the user doesn't already exist in my CACHED table called user_counts, and the first rule above updates the count.
What I'm unsure of is how do I know when which rule is called first, the update rule or insert.. And there must be a better way, how do I combine the two rules? Can this be done with a function?
It is true that postgresql is notoriously slow when it comes to count(*) queries. However if you do have a where clause that limits the number of entries the query will be much faster. If you are using postgresql 9.2 or newer this query will be just as fast as it's in mysql because of index only scans which was added in 9.2 but it's best to explain analyze your query to make sure.
Does my solution make sense?
Very much so provided that your explain analyze show that index only scans are not being used. Trigger based solutions like the one that you have adapted find wide usage. But as you have realized the problem with the initial state arises (whether to do an update or an insert).
which rule is called first
Multiple rules on the same table and same event type are applied in
alphabetical name order.
from http://www.postgresql.org/docs/9.1/static/sql-createrule.html
the same applies for triggers. If you want a particular rule to be executed first change it's name so that it comes up higher in the alphabetical order.
how do I combine the two rules?
One solution is to modify your rule to perform an upsert (Look right at the bottom of that page for a sample upsert ). The other is to populate the counter table with initial values. The trick is to create the trigger at the same time to avoid errors. This blog post explains it really well.
While the initial setup will be slow each individual insert will probably be faster. The two opposing factors being the slowness of a WHERE NOT EXISTS query vs the overhead of catching an exception.
Tip: A block containing an EXCEPTION clause is significantly more
expensive to enter and exit than a block without one. Therefore, don't
use EXCEPTION without need.
Source the postgresql documentation page linked above.

Code to assign an ID when button is clicked

I have designed a simple database to keep track of company contacts. Now, I am building a form to allow employees to add contacts to the database.
On the form itself, I have all the columns except the primary key (contactID) tied to a text box. I would like the contactID value to be (the total number of entered contacts + 1) when the Add button is clicked. Basically, the first contact entered will have a contactID of 1 (0 + 1 = 1). Maybe the COUNT command factors in?
So, I am looking for assistance with what code I should place in the .Click event. Perhaps it would help to know how similar FoxPro is to SQL.
Thanks
The method you recommend for assigning ContactIDs is not a good idea. If two people are using the application at the same time, they could each create a record with the same ContactID.
My recommendation is that you use VFP's AutoIncrementing Integer capability. That is, set the relevant column to be Integer (AutoInc) in the Table Designer. Then, each new row gets the next available value, but you don't have to do any work to make it happen.
There are various ways to do this. Probably the simplest is to attempt to lock the table with flock() when saving, and if successful do:
calc max id_field to lnMax
Then when inserting your new record use lnMax+1 as the id_field value. Don't forget to
unlock all
... after saving. You'll want to ensure that 'id_field' has an index tag on it, and that you handle the case where someone else might have the table locked.
You can also do it more 'automagically' with a stored procedure.

Filemaker: Best way to set a certain field in every related record

I have a FileMaker script which calculates a value. I have 1 record from table A from which a relation points to n records of table B. What is the best way to set B::Field to this value for each of these n related records?
Doing Set Field [B::Field; $Value] will only set the value of the first of the n related records. What works however is the following:
Go to Related Record [Show only related records; From table: "B"; Using layout: "B_layout" (B)]
Loop
Set Field [B::Field; $Value]
Go To Record/Request/Page [Next; Exit after last]
End Loop
Go to Layout [original layout]
Is there a better way to accomplish this? I dislike the fact that in order to set some value (model) programmatically (controller), I have to create a layout (view) and switch to it, even though the user is not supposed to notice anything like a changing view.
FileMaker always was primarily an end-user tool, so all its scripts are more like macros that repeat user actions. It nowhere near as flexible as programmer-oriented environments. To go to another layout is, actually, a standard method to manipulate related values. You would have to do this anyway if you, say, want to duplicate a related record or print a report.
So:
Your script is quite good, except that you can use the Replace Field Contents script step. Also add Freeze Window script step in the beginning; it will prevent the screen from updating.
If you have a portal to the related table, you may loop over portal rows.
FileMaker plug-in API can execute SQL and there are some plug-ins that expose this functionality. So if you really want, this is also an option.
I myself would prefer the first variant.
Loop through a Portal of Related Records
Looping through a portal that has the related records and setting the field has a couple of advantages over either Replace or Go To Record, Set Field Loop.
You don't have to leave the layout. The portal can be hidden or place off screen if it isn't already on the layout.
You can do it transactionally. IE you can make sure that either all the records get edited or none of them do. This is important since in a multi-user networked solution, records may not always be editable. Neither replace or looping through the records without a portal is transaction safe.
Here is some info on FileMaker transactions.
You can loop through a portal using Go To Portal Row. Like so:
Go To Portal Row [First]
Loop
Set Field [B::Field; $Value]
Go To Portal Row [Next; Exit after last]
End Loop
It depends on what you're using the value for. If you need to hard wire a certain field, then it doesn't sound like you've got a very normalised data structure. The simplest way would be a calculation in TableB instead of a stored field, or if this is something that is stored, could it be a lookup field instead that is set on record creation?
What is the field in TableB being used for and how?