
Did you know that InterBase and PostgreSQL both support a field type which is an array of values? It is not always obvious how to read and write to these database array field types. I get quite a lot of email from Delphi and C++ developers asking if I know how to achieve something they are struggling with. One such recent email was in connection with how to get database array fields to display and be updated correctly. I had to look into it because I was a little unsure myself but between the emailing developer and I we got it working perfectly. This article tells you how to do that with the power of Delphi and FireDAC along with some cool demo code you can download and use to experiment with arrays yourself. Note that array fields do not have wide support among DBMS. Neither MySQL nor SQL Server support them.
Table of Contents
What are database array fields?
Database array fields in InterBase, as the name suggests, do not contain a single value but can contain a range of values. Those values all have to be of the same type such as integers, characters, and so on, but they can be multi-dimensional, not in the Star Trek sense, sadly, it just means you can have arrays like integer[4][128]
which is an array of 4 lots of 128 integers. InterBase has supported array fields for many years and was one of the first databases to do so.

As you can see in the above IBConsole image, the field MY_ARRAY
is an array field which contains 12 elements. It’s as simple as that in InterBase. The SQL to create the above table in InterBase is below.
1 2 3 4 5 6 |
CREATE TABLE TABLE_WITH_ARRAY ( THE_YEAR INTEGER NOT NULL, MY_ARRAY INTEGER[1:12] , CONSTRAINT UNIQUE_YEAR UNIQUE (THE_YEAR) ); |
I am going to use that table in a demo project to show a 12-month series bar chart graph using the truly excellent TChart component from Steema. You probably already have it installed in RAD Studio since we ship an Embarcadero version for free.
Why would I use a database array field?
Array fields are slightly counter-intuitive for relational database systems where the preference for techniques like database normalization leans heavily in the direction of tables with references to other tables. That form of having fields that are references which link to other tables is useful to simplify and abstract data but, sometimes, it can also introduce complexity and the need to use things like foreign keys or query joins and cascading updates. There are times when all you need is to have an array of values within the actual record itself, for example to depict a series of datapoints on a graph.

Array fields can be used for far more than that, of course. They can be very useful for containing any types of data that are related to one another and where you want to have it all in one place, the actual record, rather than linked records. I have seen people use them for “other telephone numbers” fields, “previous password hashes” (to prevent reuse within N iterations), and for similar collections.
How do you define an array field type in PostgreSQL?
InterBase defines arrays in the way I showed above. For an array field type with 12 elements the range is defined as [1:12]
so the first element is [1]
and the last is [12]
. For PostgreSQL arrays are similar except at the time of writing, despite having a syntax which allows determinate array subscripts PostgreSQL doesn’t enforce them and, in fact, ignores them so they behave as open arrays. Handy, but also a little wrong.

To define the array type in PostgreSQL you can use PGAdmin:

The SQL for that is below. It creates an array field called the_minutiae
which is an array of integer values.
1 2 3 4 5 6 |
CREATE TABLE IF NOT EXISTS public.table_with_array ( the_person character varying(30) COLLATE pg_catalog."default" NOT NULL, the_minutiae integer[], CONSTRAINT table_with_array_pkey PRIMARY KEY (the_person) ) |
I’m going to use this table in a demo project which will simulate displaying the “minutiae” of a person’s fingerprints. The minutiae are the unique characteristics of a fingerprint pattern like swirls with breaks in them, arches and so on. Fun fact: koalas have fingerprints which are almost indistinguishable from human ones. 🐨
How to read and update InterBase array fields?
The demo project shows you how, but here is a brief look at the details. I used FireDAC to create the connection and then an FDTable to manage the database table containing the array field.

I added persistent fields, which makes it easier to link to visual controls using LiveBindings.


How to write to an InterBase array field type?
Once I created those persistent fields it was very easy – here’s the code which runs when the user clicks on the “fill with test data” button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
procedure TForm1.FillTestDataButtonClick(Sender: TObject); begin if not FDConnection1.Connected then ActivateDatabase; if FDConnection1.Connected then begin var sCaption: string := FillTestDataButton.Caption; CenterPanel.Visible := False; try ChangeTablesActiveStatus(False); FDQuery1.Sql.Text := 'TRUNCATE TABLE TABLE_WITH_ARRAY'; // Fastest way to empty the table FDQuery1.ExecSQL; UpdateTable.Active := True; UpdateTable.DisableControls; // prevent UI updates from slowing down our work for var TheYear := 1996 to 2034 do begin UpdateTable.Append; FillTestDataButton.Caption := TheYear.ToString; Application.ProcessMessages; UpdateTableTHE_YEAR.AsInteger := TheYear; for var TheMonth := 0 to 11 do UpdateTableMY_ARRAY.FieldValues[TheMonth] := Random(250); UpdateTable.Post; end; finally UpdateTable.EnableControls; UpdateTable.Active := False; ChangeTablesActiveStatus(True); end; FillTestDataButton.Caption := sCaption; CenterPanel.Visible := True; end; end; |
There are other ways depending on your needs, but this is pretty fast. If you were going to update many thousands of records at once, then you need to consider writing queries which leverage things like ArrayDML and other techniques. My colleague, Stephen Ball wrote about it here: https://delphiaball.co.uk/2016/04/29/interbase-array-fields-firedac/
How to read an InterBase array field?
It you define the field as I described above, the actual Delphi code to read an InterBase array field is easy. Use the FieldValues
property. Here’s a snippet from my example app. Note that although you define the array in InterBase as [1:12]
the field index value in the code begins at zero. So, array value 1 is FieldValues[0]
.
1 2 3 4 5 6 7 8 |
procedure TForm1.UpdateChart; begin Chart1.Title.Caption := ListTableTHE_YEAR.Value.ToString; Chart1.Series[0].Clear; var FS := TFormatSettings.Create; for var TheMonth := 0 to 11 do Chart1.Series[0].AddXY(TheMonth, ListTableMY_ARRAY.FieldValues[TheMonth], FS.ShortMonthNames[Succ(TheMonth)]); end; |
How to read a PostgreSQL array field?
The easiest way to read a PostgreSQL array field is to use an interposing TFDMemtable. There are other ways to do it using some of PostgreSQL specific extensions to SQL DML but I used a FireDAC memory table in my example to show how it could be done.

I created an FDTable, called ListTable
(because it is going to drive the contents of the TListBox
) which linked to the table in the database that contains the array field. I then created persistent fields the_person
and the_minutiae
. Then I added a FireDAC memory table and set the DataSetField
property to point to the ListTable’s persistent the_minutiae
field. This has the effect that every time the user or code moves the ListTable
FDTable
to a different record the memory table fills up with the array contents of the PostgreSQL array field. Cool huh? 😎
Then I can read the contents just like any regular FireDAC table:
1 2 3 4 5 6 7 |
while not FDMemTable1.Eof do begin LString := LString + LComma + FDMemTable1the_minutiae.AsString; LComma := ','; DrawDots; FDMemTable1.Next; end; |
How to write data to a table containing a PostgreSQL array field?
Once again, there is more than one way to write to a PostgreSQL array field. I chose to do it in my demo using a FireDAC query component and a SQL statement. It’s pretty easy. You could use the PostgreSQL-specific functions or FireDAC array DML. The query is a lot easier to understand though.
1 2 3 4 5 6 7 8 9 10 11 12 |
FDUpdateQuery.SQL.text := 'insert into TABLE_WITH_ARRAY values (:person, :mins)'; FDUpdateQuery.Params[1].ArrayType := atTable; FDUpdateQuery.Params[1].ArraySize := 24; // TFDParam.ArraySize must be set to array size for var PersonNumber := 1 to 128 do begin FillTestDataButton.Caption := PersonNumber.ToString; Application.ProcessMessages; FDUpdateQuery.Params[0].AsString := 'Fake person ' + Format('%.3d', [PersonNumber]); for var Minutiae := 0 to 23 do FDUpdateQuery.Params[1].Values[Minutiae] := Random(150); FDUpdateQuery.ExecSQL; end; |
Where can I find full examples of reading or writing to InterBase array fields and reading or writing to PostgreSQL array fields?
I created two repositories with full working examples of how to read and write database tables which contain array fields.
The InterBase example is here: https://github.com/checkdigits/db_arrray_test
The PostgreSQL example is here: https://github.com/checkdigits/db_arrray_test_PostgreSQL

Why not download a free trial of RAD Studio today and see why we think it’s the fastest, easiest, and most efficient way to create cross platform apps that work on Windows, macOS, Linux, iOS and Android from a single code base?
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition