9

How is it possible to create several new fields at once in the same layer, using QGIS field calculator in batch mode? There is a similar question, but using Python - I'm interested in a solution without Python.

In QGIS, using the field calculator in batch mode (from processing), it is possible to calculate several fields at once. Let's suppose a very simple case just for demonstration purpose here: an attribute table with a field named value. I now want to create 5 new fields (red box in the screenshot):

  • output_1: "value"+1
  • output_2: "value"+2
  • etc.

enter image description here

This works easy in batch mode of field calculator, using the increasing row-number: each row added will create a new field. And all input parameters can be set with Autofill... / Calculate by Expression… accordingly, writing expressions that generate the necessary values needed for each column (field calculator input parameters) in the batch dialog.

The problem now is: used in this way, QGIS will create a separate file for each row / each new field calculated: output_1, output_2 etc. If I define the same output path for each row (last column in the batch dialog window, see screenshot), than QGIS will iterate over all rows and each time overwrite the output of the previous row. Thus the result will contain only the last output, in this example with 5 rows/5 fields to create: output_5: "value"+5. When definining separate output filenames (like using increasing numbers, generated by the variable @row_number: output_1.gpkg, output_2.gpkg etc.), I get the desired result. But I get aseparate file for each field that is created.

The question: How is it possible to batch create new fields in the same layer or the same file - ideally adding the newly created fields to the attribute table of the input layer?

Screenshot: Field calculator in batch mode: field name, expression to calculate and output path are generated by an expression with Autofill... / Calculate by Expression…:

enter image description here

2
  • Have you considered using Refactor Fields to create the new fields populated by expression? It 'simulated' the batch process you are looking for and it will create only a new temporary layer with all the new fields.
    – Val P
    Feb 6, 2021 at 14:04
  • Thanks @Val P for the idea. This is a workaround that indeed produces the results I looked for. A little bit annoying is that you have to build the expression that enerates the value for each field manually. In batch mode, you can use some place holder that adapt to each field created, like "value" + @row-number in the example above. This is especially useful for creating a lot of new fields at once with a regular pattern - like starting from a datetime field, creating 365 new fields for each day of a year by adding +1, +2 +3 days etc.
    – Babel
    Feb 6, 2021 at 15:29

2 Answers 2

9
+50

You can do stuff close to that using refactor fields in batch mode or in graphical modeler. However, when not using this in combination with graphical modeler, I think it is way more convenient to use PyQGIS here. Anyways:

  1. Run Refactor Fields from processing toolbox
  2. Run as batch mode
  3. Click on "autofill" at "Fields mapping" and choose "calculate by expression":

enter image description here

Now enter your expression to generate the fields. It has to be an array of maps, following this structure of keys and values:

array(map('expression',<your_expression_for_field_values>, 'length',<field_length_as_integer>, 'name',<name_of_your_field>, 'precision',<field_precision_as_integer>, 'type',<field_type_as_integer>))

E.g. 2 stands for a 32-Bit-Integer field type. You can find a complete lookup list here: https://doc.qt.io/qt-5/qmetatype.html#Type-enum. Note that not all types are supported as QGIS fields. Here is a hint which are supported: https://github.com/qgis/qgis4.0_api/issues/49#issuecomment-237057855.

Here is an example expression to create 5 fields. However, @row_number will always return 0 in your first row, so I don't really see a point in using it. Anyway, there may be other useful expressions you can use at this point.

array(
map('expression',1+1, 'length', 0, 'name', 'intoutput_'||@row_number, 'precision',0 ,'type',2),
map('expression',concat('hello ','world'), 'length', 0, 'name', 'stringoutput_'||@row_number, 'precision',0 ,'type',10),
map('expression',True, 'length', 0, 'name', 'booloutput_'||@row_number, 'precision',0 ,'type',1),
map('expression',1.5+1.2, 'length', 0, 'name', 'floatoutput_'||@row_number, 'precision',2 ,'type',6),
map('expression',to_date(now()), 'length', 0, 'name', 'dateoutput_'||@row_number, 'precision',0 ,'type',14)
)

Which results in:

enter image description here

As you can see I don't know how to properly use string content here.

0
1

You can use a virtual layer and create new fields in the query like in this pattern:

select *, p.value+1 as output_1, p.value+2 as output_2, p.value+3 as output_3, p.value+4 as output_4, p.value+5 as output_5
from my_layer_name as p

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.