UniDac on PostgreSQL: no value on serial (autoincrement) field after insert - delphi

In my application user have ability to add some records to database.
I'am using UniDac 4.6.12 components.
For autoincrement field, we are using serial PostgreSQL type and I don't touch value of this field in my application.
But, after Post of record, the value of field is 0.
Also, I get 0 from:
Q := dmMain.aqrParts.LastInsertId;
If I refresh the dataset, record will appear with filled serial field value, but it is not comfortable way for user, because table have a lot of records, and to fetch some records to work, for user necessary to set a lot of filters.
I using this kind of properties of dataset:
object aqrParts: TUniQuery
Connection = psqlConnection
SQL.Strings = (
'SELECT * FROM parts.spareparts'
'LIMIT 200')
SpecificOptions.Strings = (
'PostgreSQL.UnpreparedExecute=True')
BeforePost = aqrPartsBeforePost
AfterPost = aqrPartsAfterPost
Left = 32
Top = 72
object aqrPartsId: TIntegerField
AutoGenerateValue = arAutoInc
FieldName = 'id'
Visible = False
end
...
Is it possible to solve this?

When you create a field with the serial type, PostgreSQL server automatically creates a sequence, and values from this sequence will be used as default for this field
To fill Id field automatically you can use two ways:
1) Set
aqrParts.Options.DefaultValues := True.
In this case default value for the Id field will be set to "nextval(''parts.spareparts_seq''::regclass)" and the Id field will be filled automatically.
2) Set
aqrParts.SpecificOptions.Values['KeySequence'] := 'spareparts_seq';
aqrParts.SpecificOptions.Values['SequenceMode'] := 'smInsert';
In this case field Id will be filled from this sequence.

This page on PostgreSQL Sequence Manipulation Functions suggests you may be able to use the nextval function to get the next value of the identity/autoincrement/sequence field before you insert. So you could get this guaranteed unique value first, then display it on the form before the user begins entering any other field values, and finally explicitly include this value in the insert statement.
Quote from the documentation on nextval function
Advance the sequence object to its next value and return that value. This is done atomically: even if multiple sessions execute nextval concurrently, each will safely receive a distinct sequence value.

Related

How to generate dynamic values in fitnesse

I have to insert incremental values in a column of the table using Fitnesse. The incremental value I'll get from a stored procedure which returns the last inserted value. So I have to increment the value and store it.
For example: I'll get a value from the stored procedure output. And I have to increment the value by 1 and insert into the table.
Any ideas?
Output from stored procedure is like : ACRDE0001 (PK)
Value to store in table : ACRDE0002, ACRDE0003, .....
Expected output
!|insert|table1|
|col1|col2|col3|
|ACRDE0001|abc|def|
|ACRDE0002|abc|def|
|ACRDE0003|abc|def|
.
.
.
.
As far as I'm aware the only way to change (e.g. increment) a value you get during your test is by writing some code in a fixture. There is a pull request to allow more dynamic Slim expression directly in the wiki, but that has not been merged (let alone released) yet.
Your questions suggests that the value is something you get from a database and that you then want to send back the generated/incremented value with new records you insert. In that case I wonder whether the increment is actually that useful to actually have in your wiki (your test case is not about the generated values, is it?).
Maybe your fixture could just retrieve the initial value (or have it supplied as constructor value) and the fixture could generate the a new value for each row and send them to the database.

Calc field doesn't post

Hi I want to post calc field(cemi) to table (sql). when I calc all field the last field doesn't post on sql table. because last field (cemi) type fkcalc how can I post fkcalc type field to sql table Thanks in advance!
procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
begin
ADOQuery1.FieldValues['cemi']:=
((ADOQuery1.FieldValues['boyuk1'] + ADOQuery1.FieldValues['boyuk2'] +
ADOQuery1.FieldValues['boyuk3'])*0.35)+((ADOQuery1.FieldValues['kicik1'] +
ADOQuery1.FieldValues['kicik2'])*0.25) +(ADOQuery1.FieldValues['qara1']*0.30);
end;
I'm not quite sure what you mean by
the last field doesn't post on sql table
If the "last field" you are referring to is your "Cemi" one and that is a column which is in the table on your SQL Server, it will not get posted back there if you have defined it as a calculated field in your AdoQuery1 in the Object Inspector. Fields with a FieldKind of fkCalculated are local to the AdoQuery.
Just assigning a value to the calculated field is sufficient to "post" it locally to the AdoQuery, as I imagine you know. What you want to do to debug your problem (because readers like me cannot debug it fr you) is to more easily see what value, if any, is being assigned to it.
From that point of view, your code is suffering from "premature optimisation" which will make it difficult for you to see what is going wrong. Try this instead:
In your ADOQuery1CalcFields, declare a local variable for each of the fields you are accessing, including the calculated one. Choose the variable types to suit the fields:
var
Boyuk1 : Double; // or Integer, etc
[...]
Cemi : Double;
Assign values to the local variables, using the AsXXXX (type) of the fields:
Cemi := 0;
if not AdoQuery1.FieldByName('Boyuk1').IsNull then
Cemi := Cemi + AdoQuery1.FieldByName('Boyuk1').AsFloat;
[etc]
That way, at least you'll be able to see the point at which the calculation goes wrong (if it does).
I've used FieldByName().AsFloat, rather than FieldValues[], because FieldValues[] is a Variant, which can be Null, and you don't want that when you are assigning values to it which mat themselves be variants.
Also
Check that AutoCalcFields is set to True for AdoQuery1.
Put a debugger breakpoint on the first line of ADOQuery1CalcFields. Compile and run and check that the breakpoint hits - if it doesn't, there's your answer. Single-step the debugger through each line of the procedure, and, after the final line, use Ctrl-F7 to evaluate the value of AdoQuery1.FieldByName('Cemi').AsFloat.

Odoo 8 - Compute Field with "store=True" can't store in database

I'm using Odoo 8 and I have a problem with compute field with type is Many2One.
Here, I declared department_id:
department_id = fields.Text(
string="Department", store=True,
comodel_name="hr.department",
compute="_get_department_id"
)
And fuction of this compute field:
#api.depends('employee_id')
def _get_department_id(self):
if self.employee_id.department_id:
self.department_id = self.employee_id.department_id.name
It seems to work right now, but it's not. In view, I can see the value of department_id. But in the database, the table has no column department_id and has no value of this column.
My question is: how can I store the department_id in database?
Notes:
In the declaration of department_id, I set store=True, but it did NOT store the value of this field in database.
I did a test. I add compute_field with type Text, It works, I don't know why compute field doesn't work with type Many2One.
#api.depends('employee_id')
def _get_compute_field(self):
if self.employee_id.department_id:
self.compute_field = self.employee_id.department_id.name
compute_field = fields.Text(
string="Compute Field", store=True,
compute="_get_compute_field"
)
The store=True works.
It may be that you added the computation to the field after it was created on the database. In this case the initial computation is not triggered.
A work around is to drop the column from the table and then upgrade your module. When the field is recreated the initial values should be computed.

Ruby on Rails+PostgreSQL: usage of custom sequences

Say I have a model called Transaction which has a :transaction_code attribute.
I want that attribute to be automatically filled with a sequence number which may differ from id (e.g. Transaction with id=1 could have transaction_code=1000).
I have tried to create a sequence on postgres and then making the default value for the transaction_code column the nextval of that sequence.
The thing is, if I do not assign any value to #transaction.transaction_code on RoR, when I issue a #transaction.save on RoR, it tries to do the following SQL:
INSERT INTO transactions (transaction_code) VALUES (NULL);
What this does is create a new row on the Transactions table, with transaction_code as NULL, instead of calculating the nextval of the sequence and inserting it on the corresponding column. Thus, as I found out, if you specify NULL to postgres, it assumes you really want to insert NULL into that column, regardless of it having a default value (I'm coming from ORACLE which has a different behavior).
I'm open to any solution on this, either if it is done on the database or on RoR:
either there is a way to exclude attributes from ActiveRecord's
save
or there is a way to change a column's value before insert with a trigger
or there is a way to generate these sequence numbers within RoR
or any other way, as long as it works :-)
Thanks in advance.
For the moment, you might be stuck fetching and assigning the sequence in your ROR model like this:
before_create :set_transaction_code_sequence
def set_transaction_code_sequence
self.transaction_code = self.class.connection.select_value("SELECT nextval('transaction_code_seq')")
end
I'm not particularily fond of this solution, since I'd like to see this corrected in AR directly... but it does do the trick.
If you want to insert the default value in to a column in an INSERT statement, you can use the keyword DEFAULT - no quotes:
INSERT INTO mytable (col1, col2) VALUES (105, DEFAULT);
Or you could spell out the default, nextval(...) in your case. See the manual here.
A trigger for that case is simple. That's actually what I would recommend if you want to make sure that only numbers from your sequence are entered, no matter what.
CREATE OR REPLACE FUNCTION trg_myseq()
RETURNS trigger AS
$BODY$
BEGIN
NEW.mycol := nextval('my_seq');
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER myseq
BEFORE INSERT
ON mytable
FOR EACH ROW
EXECUTE PROCEDURE trg_myseq();
On a side note:
If you want to assign your own (non-sequential) numbers as 'sequence', I have written a solution for that in an answer a couple of days ago:
How to specify list of values for a postgresql sequence
I was still experiencing this issue with Rails7 - I could see that Rails was generating a NULL in the insert, but changing the column from integer to bigint solved it. - Rails then does not supply a value for my sequenced column and the DEFAULT nextval('number_seq') is used.

SQL Query: Using IF statement in defining new field

I have a table with many fields and additionally several boolean fields (ex: BField1, BField2, BField3 etc.).
I need to make a Select Query, which will select all fields except for boolean ones, and a new virtual field (ex: FirstTrueBool) whose value will equal to the name of the first TRUE Boolean Field.
For ex: Say I have BField1 = False, BField2 = True, BField3 = true, BField4=false, in that case SQL Query should set [FirstTrueBool] to "BField2". Is that possible?
Thank you in advance.
P.S. I use Microsoft Access (MDB) Database and Jet Engine.
If you want to keep the current architecture (mixed 'x' non-null status and 'y' non-status fields) you have (AFAIS now) only the option to use IIF:
Select MyNonStatusField1, /* other non-status fields here */
IIF([BField1], "BField1",
IIF([BField2], "BField2",
...
IIF([BFieldLast], "BFieldLast", "#No Flag#")
))))) -- put as many parenthesis as it needs to close the imbricated IIFs
From
MyTable
Of course you can add any Where clause you like.
EDIT:
Alternatively you can use the following trick:
Set the fields to null when the flag is false and put the order number (iow, "1" for BField1, "2" for BField2 etc.) when the flag is true. Be sure that the status fields are strings (ie. Varchar(2) or, better, Char(2) in SQL terminology)
Then you can use the COALESCE function in order to return the first non-value from the status fields which will be the index number as string. Then you can add in front of this string any text you like (for example "BField"). Then you will end with something like:
Select "BField" || Coalesce(BField1, BField2, BField3, BField4) /*etc. (add as many fields you like) */
From MyTable
Much clearer IMHO.
HTH
You would be better using a single 'int' column as a bitset (provided you have up to 32 columns) to represent the columns.
e.g. see SQL Server: Updating Integer Status Columns (it's sql server, but the same technique applies equally well to MS Access)

Resources