From 3929c2d2895ddc8c21cd6e93ec0660a0f3b89f47 Mon Sep 17 00:00:00 2001 From: Arnaud Poncet-Montanges Date: Mon, 16 May 2022 13:42:45 +0200 Subject: [PATCH 1/8] Initial restructuring of working with relations --- .../working_with_vector/attribute_table.rst | 527 --------------- .../user_manual/working_with_vector/index.rst | 1 + .../working_with_vector/joins_relations.rst | 630 ++++++++++++++++++ 3 files changed, 631 insertions(+), 527 deletions(-) create mode 100644 docs/user_manual/working_with_vector/joins_relations.rst diff --git a/docs/user_manual/working_with_vector/attribute_table.rst b/docs/user_manual/working_with_vector/attribute_table.rst index d29672838eb..644f1aaab67 100644 --- a/docs/user_manual/working_with_vector/attribute_table.rst +++ b/docs/user_manual/working_with_vector/attribute_table.rst @@ -691,521 +691,6 @@ changes for all selected features at once. (see :ref:`customize_form`); it is not supported by custom ui forms. -.. index:: Relations, Foreign key -.. _vector_relations: - -Creating one or many to many relations -====================================== - -Relations are a technique often used in databases. The concept is that -features (rows) of different layers (tables) can belong to each other. - -.. _one_to_many_relation: - -Introducing 1-N relations -------------------------- - -As an example you have a layer with all regions of alaska (polygon) -which provides some attributes about its name and region type and a -unique id (which acts as primary key). - -Then you get another point layer or table with information about airports -that are located in the regions and you also want to keep track of these. If -you want to add them to the regions layer, you need to create a one to many -relation using foreign keys, because there are several airports in most regions. - -.. _figure_relations_map: - -.. figure:: img/relations1.png - :align: center - - Alaska region with airports - -Layers in 1-N relations -....................... - -QGIS makes no difference between a table and a vector layer. Basically, a vector -layer is a table with a geometry. So you can add your table as a vector layer. -To demonstrate the 1-n relation, you can load the :file:`regions` shapefile and -the :file:`airports` shapefile which has a foreign key field (``fk_region``) to -the layer regions. This means, that each airport belongs to exactly one region -while each region can have any number of airports (a typical one to many -relation). - -Foreign keys in 1-N relations -............................. - -In addition to the already existing attributes in the airports attribute table, -you'll need another field ``fk_region`` which acts as a foreign key (if you have -a database, you will probably want to define a constraint on it). - -This field fk_region will always contain an id of a region. It can be seen like -a pointer to the region it belongs to. And you can design a custom edit form -for editing and QGIS takes care of the setup. It works with different -providers (so you can also use it with shape and csv files) and all you have -to do is to tell QGIS the relations between your tables. - -Defining 1-N relations -...................... - -The first thing we are going to do is to let QGIS know about the relations -between the layers. This is done in :menuselection:`Project --> Properties...`. -Open the :guilabel:`Relations` tab and click on |symbologyAdd| :guilabel:`Add Relation`. - -* **Name** is going to be used as a title. It should be a human readable string, - describing, what the relation is used for. We will just call say **airport_relation** - in this case. -* **Referenced Layer (Parent)** also considered as parent layer, is the one with - the primary key, pointed to, so here it is the ``regions`` layer. You need to define - the primary key of the referenced layer, so it is ``ID``. -* **Referencing Layer (Child)** also considered as child layer, is the one with - the foreign key field on it. In our case, this is the ``airports`` layer. For - this layer you need to add a referencing field which points to the other - layer, so this is ``fk_region``. - - .. note:: Sometimes, you need more than a single field to uniquely identify - features in a layer. Creating a relation with such a layer requires - a **composite key**, ie more than a single pair of matching - fields. Use the |symbologyAdd| :sup:`Add new field pair as part of a composite - foreign key` button to add as many pairs as necessary. - -* **Id** will be used for internal purposes and has to be unique. You may need - it to build :ref:`custom forms `. If - you leave it empty, one will be generated for you but you can assign one - yourself to get one that is easier to handle -* **Relationship strength** sets the strength of the relation between the parent - and the child layer. The default :guilabel:`Association` type means that - the parent layer is *simply* linked to the child one while the - :guilabel:`Composition` type allows you to duplicate also the child features - when duplicating the parent ones and on deleting a feature the children are - deleted as well, resulting in cascade over all levels (means children of children - of... are deleted as well). - -.. _figure_relations_manager: - -.. figure:: img/relations2.png - :align: center - - Adding a relation between regions and airports layers - -From the :guilabel:`Relations` tab, you can also press the |symbologyAdd| -:guilabel:`Discover Relation` button to fetch the relations available from -the providers of the loaded layers. This is possible for layers stored in -data providers like PostgreSQL or SpatiaLite. - -.. index:: Feature form, Linked forms, Embedded form - -Forms for 1-N relations -....................... - -Now that QGIS knows about the relation, it will be used to improve the -forms it generates. As we did not change the default form method (autogenerated) -it will just add a new widget in our form. So let's select the layer region in -the legend and use the identify tool. Depending on your settings, the form might -open directly or you will have to choose to open it in the identification dialog -under actions. - -.. _figure_embedded_form: - -.. figure:: img/relations3.png - :align: center - - Identification dialog regions with relation to airports - -As you can see, the airports assigned to this particular region are all shown in -a table. And there are also some buttons available. Let's review them shortly: - -* The |toggleEditing| button is for toggling the edit mode. Be aware that it - toggles the edit mode of the airport layer, although we are in the feature - form of a feature from the region layer. But the table is representing - features of the airport layer. -* The |saveEdits| button is for saving all the edits in the child layer (airport). -* The |capturePoint| button lets you digitize the airport geometry in the map canvas and - assigns the new feature to the current region by default. - Note that the icon will change according to the geometry type. -* The |newTableRow| button adds a new record to the airport layer attribute table - and assigns the new feature to the current region by default. The geometry can - be drawn later with the :guilabel:`Add part` digitizing tool. -* The |duplicateFeature| button allows you to copy and paste one or more child - features within the child layer. They can later be assigned to a different - parent feature or have their attributes modified. -* The |deleteSelectedFeatures| button deletes the selected airport(s) permanently. -* The |link| symbol opens a new dialog where you can select any existing - airport which will then be assigned to the current region. This may be handy - if you created the airport on the wrong region by accident. -* The |unlink| symbol unlinks the selected airport(s) from the current region, - leaving them unassigned (the foreign key is set to NULL) effectively. -* With the |zoomToSelected| button you can zoom the map to the selected child - features. -* The two buttons |formView| and |openTable| to the right switch between the :ref:`table - view and form view ` of the related child features. - -If you use the :ref:`Drag and Drop Designer ` for the regions feature, you can select -which tools are available. You can even decide whether to open a new form when a new feature is -added using :guilabel:`Force hide form on add feature` option. Be aware that this option implies -that not null attributes must take a valid default value to work correctly. - -.. _figure_select_relation_tools: - -.. figure:: img/relations11.png - :align: center - - Drag and Drop Designer for configure regions-airports relation tools - -In the above example the referencing layer has geometries (so it isn't just -an alphanumeric table) so the above steps will create an entry in the layer -attribute table that has no corresponding geometric feature. To add the -geometry: - -#. Choose |openTable| :menuselection:`Open Attribute Table` for the referencing layer. -#. Select the record that has been added previously within the feature form of the - referenced layer. -#. Use the |addPart| :sup:`Add Part` digitizing tool to attach a geometry to the - selected attributes table record. - -If you work on the airport table, the widget Relation Reference is automatically -set up for the ``fk_region`` field (the one used to create the relation), see -:ref:`Relation Reference widget `. - -.. Todo: It could be nice that those advanced widgets get a description one day - -In the airport form you will see the |formView| button at the right side of the -``fk_region`` field: if you click on the button the form of the region layer will -be opened. This widget allows you to easily and quickly open the forms of the -linked parent features. - -.. _figure_linked_forms: - -.. figure:: img/relations4.png - :align: center - - Identification dialog airport with relation to regions - -The Relation Reference widget has also an option to embed the form of the parent -layer within the child one. It is available in the :menuselection:`Properties --> Attributes Form` -menu of the airport layer: select the ``fk_region`` field and check the -``Show embedded form`` option. - -If you look at the feature dialog now, you will see, that the form of the region -is embedded inside the airports form and will even have a combobox, which allows -you to assign the current airport to another region. - -.. _figure_linked_forms_embedded: - -.. figure:: img/relations5.png - :align: center - -Moreover if you toggle the editing mode of the airport layer, the ``fk_region`` -field has also an autocompleter function: while typing you will see all the -values of the ``id`` field of the region layer. -Here it is possible to digitize a polygon for the region layer using the |symbologyAdd| button -if you chose the option ``Allow adding new features`` in the -:menuselection:`Properties --> Attributes Form` menu of the airport layer. - -The child layer can also be used in the :ref:`select_by_value` tool in -order to select features of the parent layer based on attributes of their children. - -In :numref:`figure_select_by_value`, all the regions where the mean -altitude of the airports is greater than 500 meters above sea level -are selected. - -You will find that many different aggregation functions are available in the form. - -.. _figure_select_by_value: - -.. figure:: img/relation_select_by_value.png - :align: center - - Select parent features with child values - - -.. index:: Many-to-many relation; Relation -.. _many_to_many_relation: - -Introducing many-to-many (N-M) relations ----------------------------------------- - -N-M relations are many-to-many relations between two tables. For instance, the -``airports`` and ``airlines`` layers: an airport receives several airline -companies and an airline company flies to several airports. - -This SQL code creates the three tables we need for an N-M relationship in -a PostgreSQL/PostGIS schema named *locations*. You can run the code using the -:menuselection:`Database --> DB Manager…` for PostGIS or external tools such as `pgAdmin -`_. The airports table stores the ``airports`` layer and the airlines -table stores the ``airlines`` layer. In both tables few fields are used for -clarity. The *tricky* part is the ``airports_airlines`` table. We need it to list all -airlines for all airports (or vice versa). This kind of table is known -as a *pivot table*. The *constraints* in this table force that an airport can be -associated with an airline only if both already exist in their layers. - -.. code-block:: sql - - CREATE SCHEMA locations; - - CREATE TABLE locations.airports - ( - id serial NOT NULL, - geom geometry(Point, 4326) NOT NULL, - airport_name text NOT NULL, - CONSTRAINT airports_pkey PRIMARY KEY (id) - ); - - CREATE INDEX airports_geom_idx ON locations.airports USING gist (geom); - - CREATE TABLE locations.airlines - ( - id serial NOT NULL, - geom geometry(Point, 4326) NOT NULL, - airline_name text NOT NULL, - CONSTRAINT airlines_pkey PRIMARY KEY (id) - ); - - CREATE INDEX airlines_geom_idx ON locations.airlines USING gist (geom); - - CREATE TABLE locations.airports_airlines - ( - id serial NOT NULL, - airport_fk integer NOT NULL, - airline_fk integer NOT NULL, - CONSTRAINT airports_airlines_pkey PRIMARY KEY (id), - CONSTRAINT airports_airlines_airport_fk_fkey FOREIGN KEY (airport_fk) - REFERENCES locations.airports (id) - ON DELETE CASCADE - ON UPDATE CASCADE - DEFERRABLE INITIALLY DEFERRED, - CONSTRAINT airports_airlines_airline_fk_fkey FOREIGN KEY (airline_fk) - REFERENCES locations.airlines (id) - ON DELETE CASCADE - ON UPDATE CASCADE - DEFERRABLE INITIALLY DEFERRED - ); - -Instead of PostgreSQL you can also use GeoPackage. In this case, the three tables -can be created manually using the :menuselection:`Database --> DB Manager…`. In -GeoPackage there are no schemas so the *locations* prefix is not needed. - -Foreign key constraints in ``airports_airlines`` table can´t be created using -:menuselection:`Table --> Create Table…` or :menuselection:`Table --> Edit Table…` -so they should be created using :menuselection:`Database --> SQL Window…`. -GeoPackage doesn't support *ADD CONSTRAINT* statements so the ``airports_airlines`` -table should be created in two steps: - -#. Set up the table only with the ``id`` field using :menuselection:`Table --> Create Table…` -#. Using :menuselection:`Database --> SQL Window…`, type and execute this SQL code: - - .. code-block:: sql - - ALTER TABLE airports_airlines - ADD COLUMN airport_fk INTEGER - REFERENCES airports (id) - ON DELETE CASCADE - ON UPDATE CASCADE - DEFERRABLE INITIALLY DEFERRED; - - ALTER TABLE airports_airlines - ADD COLUMN airline_fk INTEGER - REFERENCES airlines (id) - ON DELETE CASCADE - ON UPDATE CASCADE - DEFERRABLE INITIALLY DEFERRED; - -Then in QGIS, you should set up two :ref:`one-to-many relations ` -as explained above: - -* a relation between ``airlines`` table and the pivot table; -* and a second one between ``airports`` table and the pivot table. - -An easier way to do it (only for PostgreSQL) is using the :guilabel:`Discover Relations` -in :menuselection:`Project --> Properties --> Relations`. QGIS will automatically read -all relations in your database and you only have to select the two you need. Remember -to load the three tables in the QGIS project first. - -.. _figure_setup_relations: - -.. figure:: img/relations6.png - :align: center - - Relations and autodiscover - -In case you want to remove an ``airport`` or an ``airline``, QGIS won't remove -the associated record(s) in ``airports_airlines`` table. This task will be made by -the database if we specify the right *constraints* in the pivot table creation as -in the current example. - -.. note:: **Combining N-M relation with automatic transaction group** - - You should enable the transaction mode in :menuselection:`Project Properties - --> Data Sources -->` when working on such context. QGIS should be able to - add or update row(s) in all tables (airlines, airports and the pivot tables). - -Finally we have to select the right cardinality in the -:menuselection:`Layer Properties --> Attributes Form` for the ``airports`` and -``airlines`` layers. For the first one we should choose the **airlines (id)** option -and for the second one the **airports (id)** option. - -.. _figure_cardinality: - -.. figure:: img/relations7.png - :align: center - - Set relationship cardinality - -Now you can associate an airport with an airline (or an airline with an airport) -using :guilabel:`Add child feature` or :guilabel:`Link existing child feature` -in the subforms. A record will automatically be inserted in the ``airports_airlines`` -table. - -.. _figure_relationship_working: - -.. figure:: img/relations8.png - :align: center - - N-M relationship between airports and airlines - -.. note:: Using **Many to one relation** cardinality - - Sometimes hiding the pivot table in an N-M relationship is not - desirable. Mainly because there are attributes in the relationship that can only - have values when a relationship is established. If your tables are layers (have - a geometry field) it could be interesting to activate the :guilabel:`On map identification` - option (:menuselection:`Layer Properties --> Attributes Form --> Available widgets --> Fields`) - for the foreign key fields in the pivot table. - -.. note:: **Pivot table primary key** - - Avoid using multiple fields in the primary key in a pivot table. QGIS assumes a single - primary key so a constraint like ``constraint airports_airlines_pkey primary key (airport_fk, airline_fk)`` - will not work. - - -.. index:: Polymorphic relation; Relation -.. _polymorphic_relation: - -Introducing polymorphic relations ---------------------------------- - -Polymorphic relations are special case of 1-N relations, where a single referencing (document) layer contains -the features for multiple referenced layers. This differs from normal relations which require different -referencing layer for each referenced layer. A single referencing (document) layer is achieved by adding an adiditonal -``layer_field`` column in the referencing (document) layer that stores information to identify the referenced layer. In -its most simple form, the referencing (document) layer will just insert the layer name of the referenced layer into -this field. - -To be more precise, a polymorphic relation is a set of normal relations having the same referencing -layer but having the referenced layer dynamically defined. The polymorphic setting of the layer is solved by using -an expression which has to match some properties of the referenced layer like the table name, layer id, layer name. - -Imagine we are going to the park and want to take pictures of different species of ``plants`` and ``animals`` -we see there. Each plant or animal has multiple pictures associated with it, so if we use the normal 1:N -relations to store pictures, we would need two separate tables, ``animal_images`` and ``plant_images``. -This might not be a problem for 2 tables, but imagine if we want to take separate pictures for mushrooms, birds etc. - -Polymorphic relations solve this problem as all the referencing features are stored in the same table ``documents``. -For each feature the referenced layer is stored in the ``referenced_layer`` field and the referenced -feature id in the ``referenced_fk`` field. - - -Defining polymorphic relations -.............................. - -First, let QGIS know about the polymorphic relations between the layers. This is -done in :menuselection:`Project --> Properties...`. -Open the :guilabel:`Relations` tab and click on the little down arrow next to the |symbologyAdd| -:guilabel:`Add Relation` button, so you can select the :guilabel:`Add Polymorphic Relation` option -from the newly appeared dropdown. - -.. _figure_define_polymorphic_relation: - -.. figure:: img/relations9.png - :align: center - - Adding a polymorphic relation using ``documents`` layer as referencing and ``animals`` and ``plants`` as referenced layers. - - -* **Id** will be used for internal purposes and has to be unique. You may need - it to build :ref:`custom forms `. If - you leave it empty, one will be generated for you but you can assign one - yourself to get one that is easier to handle - -* **Referencing Layer (Child)** also considered as child layer, is the one with - the foreign key field on it. In our case, this is the ``documents`` layer. For - this layer you need to add a referencing field which points to the other - layer, so this is ``referenced_fk``. - - .. note:: Sometimes, you need more than a single field to uniquely identify - features in a layer. Creating a relation with such a layer requires - a **composite key**, ie more than a single pair of matching - fields. Use the |symbologyAdd| :sup:`Add new field pair as part of a composite - foreign key` button to add as many pairs as necessary. - -* **Layer Field** is the field in the referencing table that stores the result of the evaluated - layer expression which is the referencing table that this feature belongs to. In our example, - this would be the ``referenced_layer`` field. - -* **Layer expression** evaluates to a unique identifier of the layer. This can be the layer name - ``@layer_name``, the layer id ``@layer_id``, the layer's table name ``decode_uri(@layer, 'table')`` - or anything that can uniquely identifies a layer. - -* **Relationship strength** sets the strength of the generated relations between the parent - and the child layer. The default :guilabel:`Association` type means that - the parent layer is *simply* linked to the child one while the - :guilabel:`Composition` type allows you to duplicate also the child features - when duplicating the parent ones and on deleting a feature the children are - deleted as well, resulting in cascade over all levels (means children of children - of... are deleted as well). - -* **Referenced Layers** also considered as parent layers, are those with - the primary key, pointed to, so here they would be ``plants`` and ``animals`` layers. You need to define - the primary key of the referenced layers from the dropdown, so it is ``fid``. Note that the definition of a - valid primary key requires all the referenced layers to have a field with that name. If there is no such field - you cannot save a polymorphic relation. - -Once added, the polymorphic relation can be edited via the :guilabel:`Edit Polymorphic Relation` menu entry. - -.. _figure_list_polymorphic_relations: - -.. figure:: img/relations10.png - :align: center - - Preview of the newly created polymorphic relation and it's child relations for animals and plants. - - -The example above uses the following database schema: - -.. code-block:: sql - - CREATE SCHEMA park; - - CREATE TABLE park.animals - ( - fid serial NOT NULL, - geom geometry(Point, 4326) NOT NULL, - animal_species text NOT NULL, - CONSTRAINT animals_pkey PRIMARY KEY (fid) - ); - - CREATE INDEX animals_geom_idx ON park.animals USING gist (geom); - - CREATE TABLE park.plants - ( - fid serial NOT NULL, - geom geometry(Point, 4326) NOT NULL, - plant_species text NOT NULL, - CONSTRAINT plants_pkey PRIMARY KEY (fid) - ); - - CREATE INDEX plants_geom_idx ON park.plants USING gist (geom); - - CREATE TABLE park.documents - ( - fid serial NOT NULL, - referenced_layer text NOT NULL, - referenced_fk integer NOT NULL, - image_filename text NOT NULL, - CONSTRAINT documents_pkey PRIMARY KEY (fid) - ); - .. index:: External Storage, WebDAV .. _external_storage: @@ -1310,12 +795,8 @@ from the external storage system. In that case, more details might appear in the .. |actionRun| image:: /static/common/mAction.png :width: 1.5em -.. |addPart| image:: /static/common/mActionAddPart.png - :width: 1.5em .. |calculateField| image:: /static/common/mActionCalculateField.png :width: 1.5em -.. |capturePoint| image:: /static/common/mActionCapturePoint.png - :width: 1.5em .. |checkbox| image:: /static/common/checkbox.png :width: 1.3em .. |conditionalFormatting| image:: /static/common/mActionConditionalFormatting.png @@ -1330,8 +811,6 @@ from the external storage system. In that case, more details might appear in the :width: 1.5em .. |dock| image:: /static/common/dock.png :width: 1.5em -.. |duplicateFeature| image:: /static/common/mActionDuplicateFeature.png - :width: 1.5em .. |editCut| image:: /static/common/mActionEditCut.png :width: 1.5em .. |editPaste| image:: /static/common/mActionEditPaste.png @@ -1356,8 +835,6 @@ from the external storage system. In that case, more details might appear in the :width: 1.5em .. |invertSelection| image:: /static/common/mActionInvertSelection.png :width: 1.5em -.. |link| image:: /static/common/mActionLink.png - :width: 1.5em .. |multiEdit| image:: /static/common/mActionMultiEdit.png :width: 1.5em .. |multiEditChangedValues| image:: /static/common/multieditChangedValues.png @@ -1398,16 +875,12 @@ from the external storage system. In that case, more details might appear in the :width: 1.5em .. |sort| image:: /static/common/sort.png :width: 1.5em -.. |symbologyAdd| image:: /static/common/symbologyAdd.png - :width: 1.5em .. |taskCancel| image:: /static/common/mTaskCancel.png :width: 1.5em .. |toggleEditing| image:: /static/common/mActionToggleEditing.png :width: 1.5em .. |undo| image:: /static/common/mActionUndo.png :width: 1.5em -.. |unlink| image:: /static/common/mActionUnlink.png - :width: 1.5em .. |warning| image:: /static/common/mIconWarning.png :width: 1.5em .. |zoomTo| image:: /static/common/mActionZoomTo.png diff --git a/docs/user_manual/working_with_vector/index.rst b/docs/user_manual/working_with_vector/index.rst index e6d6eea6f7f..1da527ce73e 100644 --- a/docs/user_manual/working_with_vector/index.rst +++ b/docs/user_manual/working_with_vector/index.rst @@ -10,3 +10,4 @@ vector_properties attribute_table editing_geometry_attributes + joins_relations diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst new file mode 100644 index 00000000000..f232b13f975 --- /dev/null +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -0,0 +1,630 @@ +.. index:: Joins, Relations +.. _sec_joins_relations: + +********************************** + Joins and relations +********************************** + +Joins and relations are technical concepts used in databases to get the most out of +data stored in tables by combining their contents. The concept is that +features (rows) of different layers (tables) can belong to each other. One of the +most simple example is the value list where one attribute (foreign key) of a table +is used to create a link to another table which is composed of values.Relations are +usually used to link objects (features) from two layers (tables) together. + +.. only:: html + + .. contents:: + :local: + + +.. index:: Joins, Foreign key +.. _vector_joins: + +Foreword: Joins +======================================== + +QGIS allows you to create and manage joins between tables (spatial or non spatial). +This is done on the layer level (properties). Joins enable you to define +links between an attribute of a table and a value stored in another table. + +The most simple example is not even a real join but the possibility offered by QGIS +to set a value list directly in the attribute form using the Value Map widget +(TODO : ADD link to /working_with_vector/vector_properties.html#edit-widgets) +to define mapping values manually or using a CSV or layer import. + +The second example is to use the Value Relation widget +(TODO : ADD link to /working_with_vector/vector_properties.html#edit-widgets) +to define a relation between an attribute and an other attribute contained in another layer. + +The third example is to use the Joins tab +(TODO : add link /working_with_vector/vector_properties.html#joins-properties) +to associate features of the current layer +to features from another loaded layer. The join is based on an attribute +that is shared by the layers. This enable to add one or more attribute from a table +to the other. + + +.. index:: Joins, Foreign key +.. _vector_relations: + +Foreword: Relations +======================================== + +QGIS allows you to create and manage relations between tables (spatial or non spatial). +This is done on the project level (properties). +Relations enable you to define interconnected features. +QGIS provide a wide range of functions and tools to handle related objects and forms. + +.. index:: Relations, Foreign key +.. _vector_relations_interface: + +Introducing the relations interface +========================================= + +To open the relations interface in QGIS, select the project properties menu +and then click on the Relations Tab. Here you can see all defined relations +for your project. Add, discover or remove relations. + +TODO : ADD a screen of the the relations interface + + .. note:: There is no simple way to edit a relation once it is created yet. + To edit a relation you will have then to remove and create it from scratch. + + .. note:: QGIS is able to discover existing relations from supported databases formats. + This can be a good way to ease the relations definition. + +Once a relation is created in the project properties, it can be used in the +layers forms widget Relation Reference +/working_with_vector/vector_properties.html#edit-widgets +or used in the field expression calculator to design some powerful queries and features. + + +.. _one_to_many_relation: + +Introducing 1-N relations +========================= + +As an example you have a layer with all regions of Alaska (polygon) +which provides some attributes about its name and region type +and a unique id (which acts as primary key). + +Then you get another point layer or table with information about airports +that are located in the regions and you also want to keep track of these. +If you want to add them to the regions layer, +you need to create a one to many relation using foreign keys, +because there are several airports in most regions. + +.. _figure_relations_map: + +.. figure:: img/relations1.png + :align: center + + Alaska region with airports + +Layers in 1-N relations +----------------------- + +QGIS makes no difference between a table and a vector layer. +Basically, a vector layer is a table with a geometry. +So you can add your table as a vector layer. +To demonstrate the 1-n relation, you can load the :file:`regions` shapefile +and the :file:`airports` shapefile which has a foreign key field (``fk_region``) to the layer regions. +This means, that each airport belongs to exactly one region +while each region can have any number of airports (a typical one to many relation). + +Foreign keys in 1-N relations +----------------------------- + +In addition to the already existing attributes in the airports attribute table, +you'll need another field ``fk_region`` which acts as a foreign key +(if you have a database, you will probably want to define a constraint on it). + +This field fk_region will always contain an id of a region. +It can be seen like a pointer to the region it belongs to. +And you can design a custom edit form for editing and QGIS takes care of the setup. +It works with different providers (so you can also use it with shape and csv files) +and all you have to do is to tell QGIS the relations between your tables. + +Defining 1-N relations +---------------------- + +The first thing we are going to do is to let QGIS know about the relations between the layers. +This is done in :menuselection:`Project --> Properties...`. +Open the :guilabel:`Relations` tab and click on |symbologyAdd| :guilabel:`Add Relation`. + +* **Name** is going to be used as a title. It should be a human readable string + describing what the relation is used for. + We will just call say **airport_relation** in this case. +* **Referenced Layer (Parent)** also considered as parent layer, is the one with the primary key, + pointed to, so here it is the ``regions`` layer. + You need to define the primary key of the referenced layer, so it is ``ID``. +* **Referencing Layer (Child)** also considered as child layer, + is the one with the foreign key field on it. + In our case, this is the ``airports`` layer. + For this layer you need to add a referencing field which points to the other layer, + so this is ``fk_region``. + + .. note:: Sometimes, you need more than a single field to uniquely identify features in a layer. + Creating a relation with such a layer requires a **composite key**, + i.e. more than a single pair of matching fields. + Use the |symbologyAdd| :sup:`Add new field pair as part of a composite foreign key` button + to add as many pairs as necessary. + +* **Id** will be used for internal purposes and has to be unique. + You may need it to build :ref:`custom forms `. + If you leave it empty, one will be generated for you but you can assign one yourself + to get one that is easier to handle +* **Relationship strength** sets the strength of the relation between the parent and the child layer. + The default :guilabel:`Association` type means that the parent layer is *simply* linked to the child one + while the :guilabel:`Composition` type allows you to duplicate also the child features + when duplicating the parent ones and on deleting a feature the children are deleted as well, + resulting in cascade over all levels (means children of children of... are deleted as well). + +.. _figure_relations_manager: + +.. figure:: img/relations2.png + :align: center + + Adding a relation between regions and airports layers + +From the :guilabel:`Relations` tab, you can also press the |symbologyAdd| +:guilabel:`Discover Relation` button to fetch the relations available from +the providers of the loaded layers. +This is possible for layers stored in data providers like PostgreSQL or SpatiaLite. + +.. index:: Feature form, Linked forms, Embedded form + +Forms for 1-N relations +----------------------- + +Now that QGIS knows about the relation, it will be used to improve the forms it generates. +As we did not change the default form method (autogenerated), it will just add a new widget in our form. +So let's select the layer region in the legend and use the identify tool. +Depending on your settings, the form might open directly +or you will have to choose to open it in the identification dialog under actions. + +.. _figure_embedded_form: + +.. figure:: img/relations3.png + :align: center + + Identification dialog regions with relation to airports + +As you can see, the airports assigned to this particular region are all shown in a table. +And there are also some buttons available. Let's review them shortly: + +* The |toggleEditing| button is for toggling the edit mode. + Be aware that it toggles the edit mode of the airport layer, + although we are in the feature form of a feature from the region layer. + But the table is representing features of the airport layer. +* The |saveEdits| button is for saving all the edits in the child layer (airport). +* The |capturePoint| button lets you digitize the airport geometry in the map canvas + and assigns the new feature to the current region by default. + Note that the icon will change according to the geometry type. +* The |newTableRow| button adds a new record to the airport layer attribute table + and assigns the new feature to the current region by default. + The geometry can be drawn later with the :guilabel:`Add part` digitizing tool. +* The |duplicateFeature| button allows you to copy and paste one or more child features + within the child layer. + They can later be assigned to a different parent feature or have their attributes modified. +* The |deleteSelectedFeatures| button deletes the selected airport(s) permanently. +* The |link| symbol opens a new dialog where you can select any existing airport + which will then be assigned to the current region. + This may be handy if you created the airport on the wrong region by accident. +* The |unlink| symbol unlinks the selected airport(s) from the current region, + leaving them unassigned (the foreign key is set to NULL) effectively. +* With the |zoomToSelected| button you can zoom the map to the selected child features. +* The two buttons |formView| and |openTable| to the right switch between the :ref:`table + view and form view ` of the related child features. + +If you use the :ref:`Drag and Drop Designer ` for the regions feature, +you can select which tools are available. +You can even decide whether to open a new form when a new feature is added +using :guilabel:`Force hide form on add feature` option. +Be aware that this option implies that not null attributes must take a valid default value +to work correctly. + +.. _figure_select_relation_tools: + +.. figure:: img/relations11.png + :align: center + + Drag and Drop Designer for configure regions-airports relation tools + +In the above example the referencing layer has geometries (so it isn't just an alphanumeric table) +so the above steps will create an entry in the layer attribute table +that has no corresponding geometric feature. +To add the geometry: + +#. Choose |openTable| :menuselection:`Open Attribute Table` for the referencing layer. +#. Select the record that has been added previously within the feature form of the referenced layer. +#. Use the |addPart| :sup:`Add Part` digitizing tool to attach a geometry + to the selected attributes table record. + +If you work on the airport table, the widget Relation Reference is automatically set up +for the ``fk_region`` field (the one used to create the relation), +see :ref:`Relation Reference widget `. + +.. Todo: It could be nice that those advanced widgets get a description one day + +In the airport form you will see the |formView| button at the right side of the ``fk_region`` field: +if you click on the button the form of the region layer will be opened. +This widget allows you to easily and quickly open the forms of the linked parent features. + +.. _figure_linked_forms: + +.. figure:: img/relations4.png + :align: center + + Identification dialog airport with relation to regions + +The Relation Reference widget has also an option to embed the form of the parent layer within the child one. +It is available in the :menuselection:`Properties --> Attributes Form` menu of the airport layer: +select the ``fk_region`` field and check the ``Show embedded form`` option. + +If you look at the feature dialog now, +you will see that the form of the region is embedded inside the airports form +and will even have a combobox, which allows you to assign the current airport to another region. + +.. _figure_linked_forms_embedded: + +.. figure:: img/relations5.png + :align: center + +Moreover if you toggle the editing mode of the airport layer, +the ``fk_region`` field has also an autocompleter function: +while typing you will see all the values of the ``id`` field of the region layer. +Here it is possible to digitize a polygon for the region layer using the |symbologyAdd| button +if you chose the option ``Allow adding new features`` +in the :menuselection:`Properties --> Attributes Form` menu of the airport layer. + +The child layer can also be used in the :ref:`select_by_value` tool +in order to select features of the parent layer based on attributes of their children. + +In :numref:`figure_select_by_value`, all the regions where the mean altitude +of the airports is greater than 500 meters above sea level are selected. + +You will find that many different aggregation functions are available in the form. + +.. _figure_select_by_value: + +.. figure:: img/relation_select_by_value.png + :align: center + + Select parent features with child values + + +.. index:: Many-to-many relation; Relation +.. _many_to_many_relation: + +Introducing many-to-many (N-M) relations +======================================== + +N-M relations are many-to-many relations between two tables. +For instance, the ``airports`` and ``airlines`` layers: +an airport receives several airline companies +and an airline company flies to several airports. + +This SQL code creates the three tables we need for an N-M relationship +in a PostgreSQL/PostGIS schema named *locations*. +You can run the code using the :menuselection:`Database --> DB Manager…` for PostGIS +or external tools such as `pgAdmin `_. +The airports table stores the ``airports`` layer and the airline table stores the ``airlines`` layer. +In both tables few fields are used for clarity. +The *tricky* part is the ``airports_airlines`` table. +We need it to list all airlines for all airports (or vice versa). +This kind of table is known as a *pivot table*. +The *constraints* in this table force that an airport can be associated with an airline +only if both already exist in their layers. + +.. code-block:: sql + + CREATE SCHEMA locations; + + CREATE TABLE locations.airports + ( + id serial NOT NULL, + geom geometry(Point, 4326) NOT NULL, + airport_name text NOT NULL, + CONSTRAINT airports_pkey PRIMARY KEY (id) + ); + + CREATE INDEX airports_geom_idx ON locations.airports USING gist (geom); + + CREATE TABLE locations.airlines + ( + id serial NOT NULL, + geom geometry(Point, 4326) NOT NULL, + airline_name text NOT NULL, + CONSTRAINT airlines_pkey PRIMARY KEY (id) + ); + + CREATE INDEX airlines_geom_idx ON locations.airlines USING gist (geom); + + CREATE TABLE locations.airports_airlines + ( + id serial NOT NULL, + airport_fk integer NOT NULL, + airline_fk integer NOT NULL, + CONSTRAINT airports_airlines_pkey PRIMARY KEY (id), + CONSTRAINT airports_airlines_airport_fk_fkey FOREIGN KEY (airport_fk) + REFERENCES locations.airports (id) + ON DELETE CASCADE + ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED, + CONSTRAINT airports_airlines_airline_fk_fkey FOREIGN KEY (airline_fk) + REFERENCES locations.airlines (id) + ON DELETE CASCADE + ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED + ); + +Instead of PostgreSQL you can also use GeoPackage. +In this case, the three tables can be created manually +using the :menuselection:`Database --> DB Manager…`. +In GeoPackage there are no schemas so the *locations* prefix is not needed. + +Foreign key constraints in ``airports_airlines`` table can´t be created +using :menuselection:`Table --> Create Table…` or :menuselection:`Table --> Edit Table…` +so they should be created using :menuselection:`Database --> SQL Window…`. +GeoPackage doesn't support *ADD CONSTRAINT* statements so the ``airports_airlines`` +table should be created in two steps: + +#. Set up the table only with the ``id`` field using :menuselection:`Table --> Create Table…` +#. Using :menuselection:`Database --> SQL Window…`, type and execute this SQL code: + + .. code-block:: sql + + ALTER TABLE airports_airlines + ADD COLUMN airport_fk INTEGER + REFERENCES airports (id) + ON DELETE CASCADE + ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED; + + ALTER TABLE airports_airlines + ADD COLUMN airline_fk INTEGER + REFERENCES airlines (id) + ON DELETE CASCADE + ON UPDATE CASCADE + DEFERRABLE INITIALLY DEFERRED; + +Then in QGIS, you should set up two :ref:`one-to-many relations ` +as explained above: + +* a relation between ``airlines`` table and the pivot table; +* and a second one between ``airports`` table and the pivot table. + +An easier way to do it (only for PostgreSQL) is using the :guilabel:`Discover Relations` +in :menuselection:`Project --> Properties --> Relations`. +QGIS will automatically read all relations in your database +and you only have to select the two you need. +Remember to load the three tables in the QGIS project first. + +.. _figure_setup_relations: + +.. figure:: img/relations6.png + :align: center + + Relations and autodiscover + +In case you want to remove an ``airport`` or an ``airline``, +QGIS won't remove the associated record(s) in ``airports_airlines`` table. +This task will be made by the database if we specify the right *constraints* +in the pivot table creation as in the current example. + +.. note:: **Combining N-M relation with automatic transaction group** + + You should enable the transaction mode in :menuselection:`Project Properties --> Data Sources -->` + when working on such context. + QGIS should be able to add or update row(s) in all tables (airlines, airports and the pivot tables). + +Finally we have to select the right cardinality +in the :menuselection:`Layer Properties --> Attributes Form` +for the ``airports`` and ``airlines`` layers. +For the first one we should choose the **airlines (id)** option +and for the second one the **airports (id)** option. + +.. _figure_cardinality: + +.. figure:: img/relations7.png + :align: center + + Set relationship cardinality + +Now you can associate an airport with an airline (or an airline with an airport) +using :guilabel:`Add child feature` or :guilabel:`Link existing child feature` in the subforms. +A record will automatically be inserted in the ``airports_airlines`` table. + +.. _figure_relationship_working: + +.. figure:: img/relations8.png + :align: center + + N-M relationship between airports and airlines + +.. note:: Using **Many to one relation** cardinality + + Sometimes hiding the pivot table in an N-M relationship is not desirable. + Mainly because there are attributes in the relationship that can only have values + when a relationship is established. + If your tables have a geometry field, it could be interesting to activate the :guilabel:`On map identification` option + (:menuselection:`Layer Properties --> Attributes Form --> Available widgets --> Fields`) + for the foreign key fields in the pivot table. + +.. note:: **Pivot table primary key** + + Avoid using multiple fields in the primary key in a pivot table. + QGIS assumes a single primary key so a constraint like + ``constraint airports_airlines_pkey primary key (airport_fk, airline_fk)`` will not work. + + +.. index:: Polymorphic relation; Relation +.. _polymorphic_relation: + +Introducing polymorphic relations +================================= + +Polymorphic relations are special case of 1-N relations, +where a single referencing (document) layer contains the features for multiple referenced layers. +This differs from normal relations which require different referencing layer for each referenced layer. +A single referencing (document) layer is achieved by adding an adiditonal ``layer_field`` column +in the referencing (document) layer that stores information to identify the referenced layer. +In its most simple form, the referencing (document) layer will just insert the layer name +of the referenced layer into this field. + +To be more precise, a polymorphic relation is a set of normal relations +having the same referencing layer but having the referenced layer dynamically defined. +The polymorphic setting of the layer is solved by using an expression +which has to match some properties of the referenced layer like the table name, layer id, layer name. + +Imagine we are going to the park and want to take pictures of different species +of ``plants`` and ``animals`` we see there. +Each plant or animal has multiple pictures associated with it, +so if we use the normal 1:N relations to store pictures, we would need two separate tables, +``animal_images`` and ``plant_images``. +This might not be a problem for 2 tables, but imagine if we want to take separate pictures +for mushrooms, birds etc. + +Polymorphic relations solve this problem as all the referencing features are stored +in the same table ``documents``. +For each feature the referenced layer is stored in the ``referenced_layer`` field +and the referenced feature id in the ``referenced_fk`` field. + + +Defining polymorphic relations +------------------------------ + +First, let QGIS know about the polymorphic relations between the layers. +This is done in :menuselection:`Project --> Properties...`. +Open the :guilabel:`Relations` tab and click on the little down arrow next to the |symbologyAdd| +:guilabel:`Add Relation` button, so you can select the :guilabel:`Add Polymorphic Relation` option +from the newly appeared dropdown. + +.. _figure_define_polymorphic_relation: + +.. figure:: img/relations9.png + :align: center + + Adding a polymorphic relation using ``documents`` layer as referencing and ``animals`` and ``plants`` as referenced layers. + + +* **Id** will be used for internal purposes and has to be unique. + You may need it to build :ref:`custom forms `. + If you leave it empty, one will be generated for you but you can assign one yourself + to get one that is easier to handle + +* **Referencing Layer (Child)** also considered as child layer, + is the one with the foreign key field on it. + In our case, this is the ``documents`` layer. + For this layer you need to add a referencing field which points to the other layer, + so this is ``referenced_fk``. + + .. note:: Sometimes, you need more than a single field to uniquely identify features in a layer. + Creating a relation with such a layer requires a **composite key**, + i.e. more than a single pair of matching fields. + Use the |symbologyAdd| :sup:`Add new field pair as part of a composite foreign key` button + to add as many pairs as necessary. + +* **Layer Field** is the field in the referencing table that stores the result + of the evaluated layer expression which is the referencing table that this feature belongs to. + In our example, this would be the ``referenced_layer`` field. + +* **Layer expression** evaluates to a unique identifier of the layer. + This can be the layer name ``@layer_name``, the layer id ``@layer_id``, + the layer's table name ``decode_uri(@layer, 'table')`` + or anything that can uniquely identifies a layer. + +* **Relationship strength** sets the strength of the generated relations between the parent and the child layer. + The default :guilabel:`Association` type means that the parent layer is *simply* linked to the child one + while the :guilabel:`Composition` type allows you to duplicate also the child features + when duplicating the parent ones and on deleting a feature the children are deleted as well, + resulting in cascade over all levels (means children of children of... are deleted as well). + +* **Referenced Layers** also considered as parent layers, are those with the primary key, + pointed to, so here they would be ``plants`` and ``animals`` layers. + You need to define the primary key of the referenced layers from the dropdown, so it is ``fid``. + Note that the definition of a valid primary key requires all the referenced layers + to have a field with that name. + If there is no such field you cannot save a polymorphic relation. + +Once added, the polymorphic relation can be edited +via the :guilabel:`Edit Polymorphic Relation` menu entry. + +.. _figure_list_polymorphic_relations: + +.. figure:: img/relations10.png + :align: center + + Preview of the newly created polymorphic relation and it's child relations for animals and plants. + + +The example above uses the following database schema: + +.. code-block:: sql + + CREATE SCHEMA park; + + CREATE TABLE park.animals + ( + fid serial NOT NULL, + geom geometry(Point, 4326) NOT NULL, + animal_species text NOT NULL, + CONSTRAINT animals_pkey PRIMARY KEY (fid) + ); + + CREATE INDEX animals_geom_idx ON park.animals USING gist (geom); + + CREATE TABLE park.plants + ( + fid serial NOT NULL, + geom geometry(Point, 4326) NOT NULL, + plant_species text NOT NULL, + CONSTRAINT plants_pkey PRIMARY KEY (fid) + ); + + CREATE INDEX plants_geom_idx ON park.plants USING gist (geom); + + CREATE TABLE park.documents + ( + fid serial NOT NULL, + referenced_layer text NOT NULL, + referenced_fk integer NOT NULL, + image_filename text NOT NULL, + CONSTRAINT documents_pkey PRIMARY KEY (fid) + ); + + +.. Substitutions definitions - AVOID EDITING PAST THIS LINE + This will be automatically updated by the find_set_subst.py script. + If you need to create a new substitution manually, + please add it also to the substitutions.txt file in the + source folder. + +.. |addPart| image:: /static/common/mActionAddPart.png + :width: 1.5em +.. |capturePoint| image:: /static/common/mActionCapturePoint.png + :width: 1.5em +.. |deleteSelectedFeatures| image:: /static/common/mActionDeleteSelectedFeatures.png + :width: 1.5em +.. |duplicateFeature| image:: /static/common/mActionDuplicateFeature.png + :width: 1.5em +.. |formView| image:: /static/common/mActionFormView.png + :width: 1.2em +.. |link| image:: /static/common/mActionLink.png + :width: 1.5em +.. |newTableRow| image:: /static/common/mActionNewTableRow.png + :width: 1.5em +.. |openTable| image:: /static/common/mActionOpenTable.png + :width: 1.5em +.. |saveEdits| image:: /static/common/mActionSaveEdits.png + :width: 1.5em +.. |symbologyAdd| image:: /static/common/symbologyAdd.png + :width: 1.5em +.. |toggleEditing| image:: /static/common/mActionToggleEditing.png + :width: 1.5em +.. |unlink| image:: /static/common/mActionUnlink.png + :width: 1.5em +.. |zoomToSelected| image:: /static/common/mActionZoomToSelected.png + :width: 1.5em From eb0eb047f543800bb69889acab80ae9e4330d482 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Wed, 2 Aug 2023 14:58:48 +0000 Subject: [PATCH 2/8] Use a legible and meaningful name for relation-related screenshots --- ...relations8.png => add_airport_airline.png} | Bin ...{relations4.png => airport_attributes.png} | Bin ...s5.png => airport_attributes_expanded.png} | Bin ...ons3.png => airport_relation_dataview.png} | Bin ...ng => airport_relation_formproperties.png} | Bin ...ns6.png => airports_airlines_relation.png} | Bin ...orts_airlines_relation_formproperties.png} | Bin ...ng => polymorphic_relation_properties.png} | Bin ...ations10.png => polymorphic_relations.png} | Bin ...ions2.png => regions_airports_mapping.png} | Bin ...lations1.png => regions_with_airports.png} | Bin .../working_with_vector/joins_relations.rst | 24 +++++++++--------- 12 files changed, 12 insertions(+), 12 deletions(-) rename docs/user_manual/working_with_vector/img/{relations8.png => add_airport_airline.png} (100%) rename docs/user_manual/working_with_vector/img/{relations4.png => airport_attributes.png} (100%) rename docs/user_manual/working_with_vector/img/{relations5.png => airport_attributes_expanded.png} (100%) rename docs/user_manual/working_with_vector/img/{relations3.png => airport_relation_dataview.png} (100%) rename docs/user_manual/working_with_vector/img/{relations11.png => airport_relation_formproperties.png} (100%) rename docs/user_manual/working_with_vector/img/{relations6.png => airports_airlines_relation.png} (100%) rename docs/user_manual/working_with_vector/img/{relations7.png => airports_airlines_relation_formproperties.png} (100%) rename docs/user_manual/working_with_vector/img/{relations9.png => polymorphic_relation_properties.png} (100%) rename docs/user_manual/working_with_vector/img/{relations10.png => polymorphic_relations.png} (100%) rename docs/user_manual/working_with_vector/img/{relations2.png => regions_airports_mapping.png} (100%) rename docs/user_manual/working_with_vector/img/{relations1.png => regions_with_airports.png} (100%) diff --git a/docs/user_manual/working_with_vector/img/relations8.png b/docs/user_manual/working_with_vector/img/add_airport_airline.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations8.png rename to docs/user_manual/working_with_vector/img/add_airport_airline.png diff --git a/docs/user_manual/working_with_vector/img/relations4.png b/docs/user_manual/working_with_vector/img/airport_attributes.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations4.png rename to docs/user_manual/working_with_vector/img/airport_attributes.png diff --git a/docs/user_manual/working_with_vector/img/relations5.png b/docs/user_manual/working_with_vector/img/airport_attributes_expanded.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations5.png rename to docs/user_manual/working_with_vector/img/airport_attributes_expanded.png diff --git a/docs/user_manual/working_with_vector/img/relations3.png b/docs/user_manual/working_with_vector/img/airport_relation_dataview.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations3.png rename to docs/user_manual/working_with_vector/img/airport_relation_dataview.png diff --git a/docs/user_manual/working_with_vector/img/relations11.png b/docs/user_manual/working_with_vector/img/airport_relation_formproperties.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations11.png rename to docs/user_manual/working_with_vector/img/airport_relation_formproperties.png diff --git a/docs/user_manual/working_with_vector/img/relations6.png b/docs/user_manual/working_with_vector/img/airports_airlines_relation.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations6.png rename to docs/user_manual/working_with_vector/img/airports_airlines_relation.png diff --git a/docs/user_manual/working_with_vector/img/relations7.png b/docs/user_manual/working_with_vector/img/airports_airlines_relation_formproperties.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations7.png rename to docs/user_manual/working_with_vector/img/airports_airlines_relation_formproperties.png diff --git a/docs/user_manual/working_with_vector/img/relations9.png b/docs/user_manual/working_with_vector/img/polymorphic_relation_properties.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations9.png rename to docs/user_manual/working_with_vector/img/polymorphic_relation_properties.png diff --git a/docs/user_manual/working_with_vector/img/relations10.png b/docs/user_manual/working_with_vector/img/polymorphic_relations.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations10.png rename to docs/user_manual/working_with_vector/img/polymorphic_relations.png diff --git a/docs/user_manual/working_with_vector/img/relations2.png b/docs/user_manual/working_with_vector/img/regions_airports_mapping.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations2.png rename to docs/user_manual/working_with_vector/img/regions_airports_mapping.png diff --git a/docs/user_manual/working_with_vector/img/relations1.png b/docs/user_manual/working_with_vector/img/regions_with_airports.png similarity index 100% rename from docs/user_manual/working_with_vector/img/relations1.png rename to docs/user_manual/working_with_vector/img/regions_with_airports.png diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index f232b13f975..102f197dd86 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -97,7 +97,7 @@ because there are several airports in most regions. .. _figure_relations_map: -.. figure:: img/relations1.png +.. figure:: img/regions_with_airports.png :align: center Alaska region with airports @@ -163,7 +163,7 @@ Open the :guilabel:`Relations` tab and click on |symbologyAdd| :guilabel:`Add Re .. _figure_relations_manager: -.. figure:: img/relations2.png +.. figure:: img/regions_airports_mapping.png :align: center Adding a relation between regions and airports layers @@ -186,7 +186,7 @@ or you will have to choose to open it in the identification dialog under actions .. _figure_embedded_form: -.. figure:: img/relations3.png +.. figure:: img/airport_relation_dataview.png :align: center Identification dialog regions with relation to airports @@ -227,7 +227,7 @@ to work correctly. .. _figure_select_relation_tools: -.. figure:: img/relations11.png +.. figure:: img/airport_relation_formproperties.png :align: center Drag and Drop Designer for configure regions-airports relation tools @@ -254,7 +254,7 @@ This widget allows you to easily and quickly open the forms of the linked parent .. _figure_linked_forms: -.. figure:: img/relations4.png +.. figure:: img/airport_attributes.png :align: center Identification dialog airport with relation to regions @@ -269,7 +269,7 @@ and will even have a combobox, which allows you to assign the current airport to .. _figure_linked_forms_embedded: -.. figure:: img/relations5.png +.. figure:: img/airport_attributes_expanded.png :align: center Moreover if you toggle the editing mode of the airport layer, @@ -404,7 +404,7 @@ Remember to load the three tables in the QGIS project first. .. _figure_setup_relations: -.. figure:: img/relations6.png +.. figure:: img/airports_airlines_relation.png :align: center Relations and autodiscover @@ -428,7 +428,7 @@ and for the second one the **airports (id)** option. .. _figure_cardinality: -.. figure:: img/relations7.png +.. figure:: img/airports_airlines_relation_formproperties.png :align: center Set relationship cardinality @@ -439,7 +439,7 @@ A record will automatically be inserted in the ``airports_airlines`` table. .. _figure_relationship_working: -.. figure:: img/relations8.png +.. figure:: img/add_airport_airline.png :align: center N-M relationship between airports and airlines @@ -504,7 +504,7 @@ from the newly appeared dropdown. .. _figure_define_polymorphic_relation: -.. figure:: img/relations9.png +.. figure:: img/polymorphic_relation_properties.png :align: center Adding a polymorphic relation using ``documents`` layer as referencing and ``animals`` and ``plants`` as referenced layers. @@ -554,10 +554,10 @@ via the :guilabel:`Edit Polymorphic Relation` menu entry. .. _figure_list_polymorphic_relations: -.. figure:: img/relations10.png +.. figure:: img/polymorphic_relations.png :align: center - Preview of the newly created polymorphic relation and it's child relations for animals and plants. + Preview of the newly created polymorphic relation and its child relations for animals and plants. The example above uses the following database schema: From 9f78a2d7bdf24dcdd7ee8e7f8f276803cb040354 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Sat, 5 Aug 2023 18:12:03 +0000 Subject: [PATCH 3/8] Move the Joins properties section to the new chapter --- .../working_with_vector/joins_relations.rst | 77 ++++++++++++++++++- .../working_with_vector/vector_properties.rst | 72 ++--------------- 2 files changed, 79 insertions(+), 70 deletions(-) diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index 102f197dd86..3537cb18f46 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -18,25 +18,29 @@ usually used to link objects (features) from two layers (tables) together. :local: -.. index:: Joins, Foreign key -.. _vector_joins: -Foreword: Joins -======================================== QGIS allows you to create and manage joins between tables (spatial or non spatial). This is done on the layer level (properties). Joins enable you to define links between an attribute of a table and a value stored in another table. +.. index:: Joins, Foreign key +.. _`sec_joins`: The most simple example is not even a real join but the possibility offered by QGIS to set a value list directly in the attribute form using the Value Map widget (TODO : ADD link to /working_with_vector/vector_properties.html#edit-widgets) to define mapping values manually or using a CSV or layer import. +Joining features between two layers +==================================== The second example is to use the Value Relation widget (TODO : ADD link to /working_with_vector/vector_properties.html#edit-widgets) to define a relation between an attribute and an other attribute contained in another layer. +**Joins** allow you to associate features of the current layer +to features from another loaded vector layer. +Whether they are spatially enabled and their geometry type does not matter. +The join is based on an attribute that is shared by the layers, in a one-to-one relationship. The third example is to use the Joins tab (TODO : add link /working_with_vector/vector_properties.html#joins-properties) to associate features of the current layer @@ -44,9 +48,62 @@ to features from another loaded layer. The join is based on an attribute that is shared by the layers. This enable to add one or more attribute from a table to the other. +To create a join on a layer (identified as ``target layer``): +#. Go to the layer :menuselection:`Properties -->` |join| :guilabel:`Joins` tab +#. Click the |symbologyAdd| :sup:`Add new join` button. + The :guilabel:`Add vector join` dialog appears. +#. Select the :guilabel:`Join layer` you want to connect with the target vector layer +#. Specify the :guilabel:`Join field` and the :guilabel:`Target field` + that are common to both the join layer and the target layer .. index:: Joins, Foreign key .. _vector_relations: +#. Press :guilabel:`OK` and a summary of selected parameters is added to the :guilabel:`Join` panel. + +.. _figure_joins: + +.. figure:: img/join_attributes.png + :align: center + + Join an attribute table to an existing vector layer + +The steps above will create a join, +where **ALL** the attributes of the first matching feature in the join layer +is added to the target layer's feature. +QGIS provides more options to tweak the join: + +* |checkbox| :guilabel:`Cache join layer in virtual memory`: allows you to cache values + in memory (without geometries) from the joined layer in order to speed up lookups. +* |unchecked| :guilabel:`Create attribute index on the join field` to speed up lookups +* |unchecked| :guilabel:`Dynamic form`: helps to synchronize join fields on the fly, + according to the :guilabel:`Target field`. + This way, constraints for join fields are also correctly updated. + Note that it's deactivated by default because it may be very time consuming + if you have a lot of features or a myriad of joins. +* If the target layer is editable, then some icons will be displayed + in the attribute table next to fields, in order to inform about their status: + + * |joinNotEditable|: the join layer is not configured to be editable. + If you want to be able to edit join features from the target attribute table, + then you have to check the option |checkbox| :guilabel:`Editable join layer`. + * |joinedLayerNotEditable|: the join layer is well configured to be editable, + but its current status is read only. + * |joinHasNotUpsertOnEdit|: the join layer is editable, + but synchronization mechanisms are not activated. + If you want to automatically add a feature in the join layer + when a feature is created in the target layer, + then you have to check the option |checkbox| :guilabel:`Upsert on edit`. + Symmetrically, the option |checkbox| :guilabel:`Delete cascade` may be activated + if you want to automatically delete join features. +* |unchecked| :guilabel:`Joined fields`: instead of adding all the fields from the joined layer, + you can specify a subset. +* |unchecked| :guilabel:`Custom field name prefix` for joined fields, + in order to avoid name collision + +QGIS currently has support for joining non-spatial table formats supported by GDAL +(e.g., CSV, DBF and Excel), delimited text and the PostgreSQL providers. + +.. is the above still true? No more supported formats (oracle, mssql, ...)??? Foreword: Relations ======================================== @@ -606,12 +663,22 @@ The example above uses the following database schema: :width: 1.5em .. |capturePoint| image:: /static/common/mActionCapturePoint.png :width: 1.5em +.. |checkbox| image:: /static/common/checkbox.png + :width: 1.3em .. |deleteSelectedFeatures| image:: /static/common/mActionDeleteSelectedFeatures.png :width: 1.5em .. |duplicateFeature| image:: /static/common/mActionDuplicateFeature.png :width: 1.5em .. |formView| image:: /static/common/mActionFormView.png :width: 1.2em +.. |join| image:: /static/common/join.png + :width: 2em +.. |joinHasNotUpsertOnEdit| image:: /static/common/mIconJoinHasNotUpsertOnEdit.png + :width: 1.5em +.. |joinNotEditable| image:: /static/common/mIconJoinNotEditable.png + :width: 1.5em +.. |joinedLayerNotEditable| image:: /static/common/mIconJoinedLayerNotEditable.png + :width: 1.5em .. |link| image:: /static/common/mActionLink.png :width: 1.5em .. |newTableRow| image:: /static/common/mActionNewTableRow.png @@ -624,6 +691,8 @@ The example above uses the following database schema: :width: 1.5em .. |toggleEditing| image:: /static/common/mActionToggleEditing.png :width: 1.5em +.. |unchecked| image:: /static/common/unchecked.png + :width: 1.3em .. |unlink| image:: /static/common/mActionUnlink.png :width: 1.5em .. |zoomToSelected| image:: /static/common/mActionZoomToSelected.png diff --git a/docs/user_manual/working_with_vector/vector_properties.rst b/docs/user_manual/working_with_vector/vector_properties.rst index 3c06dd4657e..996965ceb8f 100644 --- a/docs/user_manual/working_with_vector/vector_properties.rst +++ b/docs/user_manual/working_with_vector/vector_properties.rst @@ -35,7 +35,7 @@ The vector :guilabel:`Layer Properties` dialog provides the following sections: * - |diagram| :ref:`Diagrams ` - |sourceFields| :ref:`Fields ` - |formView| :ref:`Attributes Form ` - * - |join| :ref:`Joins ` + * - |join| :ref:`Joins ` - |auxiliaryStorage| :ref:`Auxiliary Storage ` - |action| :ref:`Actions ` * - |display| :ref:`Display ` @@ -2545,70 +2545,16 @@ with the field type. The available widgets are: .. index:: Jointure, Join layers -.. _`sec_joins`: +.. _vector_joins: Joins Properties ================ The |join| :guilabel:`Joins` tab allows you to associate features -of the current layer (called ``Target layer``) to features from another -loaded vector layer (or table). The join is based on an attribute that is shared by the -layers. The layers can be geometryless (tables) or not but their join attribute -should be of the same type. - -To create a join: - -#. Click the |symbologyAdd| :sup:`Add new join` button. The :guilabel:`Add vector - join` dialog appears. -#. Select the :guilabel:`Join layer` you want to connect with the target vector - layer -#. Specify the :guilabel:`Join field` and the :guilabel:`Target field` that are - common to both the join layer and the target layer -#. Press :guilabel:`OK` and a summary of selected parameters is added to the - :guilabel:`Join` panel. - -.. _figure_joins: - -.. figure:: img/join_attributes.png - :align: center - - Join an attribute table to an existing vector layer - -The steps above will create a join, where **ALL** the attributes of the -first matching feature in the join layer is added to the target layer's feature. -QGIS provides more options to tweak the join: - -* |checkbox| :guilabel:`Cache join layer in virtual memory`: allows you to cache - values in memory (without geometries) from the joined layer in order to speed - up lookups. -* |unchecked| :guilabel:`Create attribute index on the join field` -* |unchecked| :guilabel:`Dynamic form`: helps to synchronize join fields on the - fly, according to the :guilabel:`Target field`. This way, constraints for - join fields are also correctly updated. Note that it's deactivated by default - because it may be very time consuming if you have a lot of features or a - myriad of joins. -* If the target layer is editable, then some icons will be displayed in the - attribute table next to fields, in order to inform about their status: - - * |joinNotEditable|: the join layer is not configured to be - editable. If you want to be able to edit join features from the target - attribute table, then you have to check the option - |checkbox| :guilabel:`Editable join layer`. - * |joinedLayerNotEditable|: the join layer is well configured to be - editable, but its current status is read only. - * |joinHasNotUpsertOnEdit|: the join layer is editable, but synchronization - mechanisms are not activated. If you want to automatically add a feature in - the join layer when a feature is created in the target layer, then you have - to check the option |checkbox| :guilabel:`Upsert on edit`. Symmetrically, - the option |checkbox| :guilabel:`Delete cascade` may be activated if you - want to automatically delete join features. -* |unchecked| :guilabel:`Joined fields`: instead of adding all the fields from - the joined layer, you can specify a subset. -* |unchecked| :guilabel:`Custom field name prefix` for joined fields, in order - to avoid name collision - -QGIS currently has support for joining non-spatial table formats supported by -GDAL (e.g., CSV, DBF and Excel), delimited text and the PostgreSQL providers. +of the current layer to features from another loaded vector layer (or table). +The join is based on an attribute that is shared by the layers, +in a one-to-one relationship. +For more details on joins, please read :ref:`sec_joins`. .. _vector_auxiliary_storage: @@ -3757,12 +3703,6 @@ To do so: :width: 1.5em .. |join| image:: /static/common/join.png :width: 2em -.. |joinHasNotUpsertOnEdit| image:: /static/common/mIconJoinHasNotUpsertOnEdit.png - :width: 1.5em -.. |joinNotEditable| image:: /static/common/mIconJoinNotEditable.png - :width: 1.5em -.. |joinedLayerNotEditable| image:: /static/common/mIconJoinedLayerNotEditable.png - :width: 1.5em .. |labelbackground| image:: /static/common/labelbackground.png :width: 1.5em .. |labelbuffer| image:: /static/common/labelbuffer.png From fee1eb89f446738a208aa038ebea200aac51d3f1 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Sat, 5 Aug 2023 20:20:28 +0000 Subject: [PATCH 4/8] Add some clarification to the join process --- .../working_with_vector/joins_relations.rst | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index 3537cb18f46..122c088652d 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -48,14 +48,16 @@ to features from another loaded layer. The join is based on an attribute that is shared by the layers. This enable to add one or more attribute from a table to the other. -To create a join on a layer (identified as ``target layer``): +To create a join on a layer (identified below as ``target layer``): #. Go to the layer :menuselection:`Properties -->` |join| :guilabel:`Joins` tab #. Click the |symbologyAdd| :sup:`Add new join` button. The :guilabel:`Add vector join` dialog appears. #. Select the :guilabel:`Join layer` you want to connect with the target vector layer -#. Specify the :guilabel:`Join field` and the :guilabel:`Target field` - that are common to both the join layer and the target layer +#. Specify the :guilabel:`Join field` (from the ``join layer``) + and the :guilabel:`Target field` (from the ``target layer``). + These are the fields that are used to find matching feature in both layers + hence they should have values in common. .. index:: Joins, Foreign key .. _vector_relations: #. Press :guilabel:`OK` and a summary of selected parameters is added to the :guilabel:`Join` panel. @@ -70,7 +72,17 @@ To create a join on a layer (identified as ``target layer``): The steps above will create a join, where **ALL** the attributes of the first matching feature in the join layer is added to the target layer's feature. -QGIS provides more options to tweak the join: +The following logic is used to pair features during a join process: + +* All the features in the target layer are returned, regardless they have a match +* If the target field contains duplicate values, these features are assigned the same feature + from the join layer. +* If the join field contains duplicate matching values, only the first fetched feature is picked. + +.. note:: Joins in QGIS are based on a single field matching so most of the times, + you would want to make sure that values in the matchable fields are unique. + +QGIS provides some more options to tweak the join: * |checkbox| :guilabel:`Cache join layer in virtual memory`: allows you to cache values in memory (without geometries) from the joined layer in order to speed up lookups. From 17e77dcea8aa68d5f6cc096220b3b0442a8ac714 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Fri, 11 Aug 2023 07:08:27 +0000 Subject: [PATCH 5/8] Simplify relations sectioning and adjust description with dataset --- .../introduction/qgis_configuration.rst | 14 ++-- .../working_with_vector/joins_relations.rst | 70 +++++++++---------- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/docs/user_manual/introduction/qgis_configuration.rst b/docs/user_manual/introduction/qgis_configuration.rst index cc526c91ffb..7d2fd97a8a9 100644 --- a/docs/user_manual/introduction/qgis_configuration.rst +++ b/docs/user_manual/introduction/qgis_configuration.rst @@ -1866,13 +1866,13 @@ In the |openTable| :guilabel:`Data Sources` tab, you can: Relations Properties -------------------- -The |relations| :guilabel:`Relations` tab is used to define 1:n relations and -polymorphic relations. The relations -are defined in the project properties dialog. Once relations exist for a layer, -a new user interface element in the form view (e.g. when identifying a feature -and opening its form) will list the related entities. This provides a powerful -way to express e.g. the inspection history on a length of pipeline or road segment. -You can find out more about 1:n relations support in Section :ref:`vector_relations`. +The |relations| :guilabel:`Relations` tab is used to define relations between layers. +The relations can be of one to one, many to many or polymorphic type. +They are defined in the project properties dialog. +Once relations exist for a layer, a new user interface element in the form view +(e.g. when identifying a feature and opening its form) will list the related entities. +This provides a powerful way to express e.g. the inspection history on a length of pipeline or road segment. +You can find out more about relations support in section :ref:`vector_relations`. .. _figure_relations_tab: diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index 122c088652d..924771b9743 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -58,8 +58,6 @@ To create a join on a layer (identified below as ``target layer``): and the :guilabel:`Target field` (from the ``target layer``). These are the fields that are used to find matching feature in both layers hence they should have values in common. -.. index:: Joins, Foreign key -.. _vector_relations: #. Press :guilabel:`OK` and a summary of selected parameters is added to the :guilabel:`Join` panel. .. _figure_joins: @@ -117,23 +115,18 @@ QGIS currently has support for joining non-spatial table formats supported by GD .. is the above still true? No more supported formats (oracle, mssql, ...)??? -Foreword: Relations -======================================== -QGIS allows you to create and manage relations between tables (spatial or non spatial). -This is done on the project level (properties). -Relations enable you to define interconnected features. -QGIS provide a wide range of functions and tools to handle related objects and forms. .. index:: Relations, Foreign key -.. _vector_relations_interface: +.. _vector_relations: -Introducing the relations interface +Setting relations between multiple layers ========================================= -To open the relations interface in QGIS, select the project properties menu -and then click on the Relations Tab. Here you can see all defined relations -for your project. Add, discover or remove relations. +Unlike joins that define a one-to-one link between features across two layers, +relations help you build interconnections between multiple features across two or more layers. +As such, relations are project level settings +and are set in :menuselection:`Project --> Properties -->` |relations| :guilabel:`Relations` tab. TODO : ADD a screen of the the relations interface @@ -151,8 +144,8 @@ or used in the field expression calculator to design some powerful queries and f .. _one_to_many_relation: -Introducing 1-N relations -========================= +One to many (1-N) relations +--------------------------- As an example you have a layer with all regions of Alaska (polygon) which provides some attributes about its name and region type @@ -171,32 +164,31 @@ because there are several airports in most regions. Alaska region with airports -Layers in 1-N relations ------------------------ +Layers and keys +....................... QGIS makes no difference between a table and a vector layer. Basically, a vector layer is a table with a geometry. So you can add your table as a vector layer. -To demonstrate the 1-n relation, you can load the :file:`regions` shapefile -and the :file:`airports` shapefile which has a foreign key field (``fk_region``) to the layer regions. -This means, that each airport belongs to exactly one region +To demonstrate the 1-n relation, you can load the :file:`regions` +and :file:`airports` layers in the sample dataset. +In practice, each airport belongs to exactly one region while each region can have any number of airports (a typical one to many relation). -Foreign keys in 1-N relations ------------------------------ +which has a foreign key field (``fk_region``) to the layer regions. -In addition to the already existing attributes in the airports attribute table, -you'll need another field ``fk_region`` which acts as a foreign key +In addition to the attributes describing the airports, +the aiports layer has another field ``fk_region`` which acts as a foreign key (if you have a database, you will probably want to define a constraint on it). - -This field fk_region will always contain an id of a region. +This ``fk_region`` field will always contain an id of a region. It can be seen like a pointer to the region it belongs to. -And you can design a custom edit form for editing and QGIS takes care of the setup. -It works with different providers (so you can also use it with shape and csv files) -and all you have to do is to tell QGIS the relations between your tables. + +All you have to do is to tell QGIS the relation between the layers +so that you can design a custom edit form for editing and QGIS takes care of the setup. +It works with different providers (so you can also use it with shape and csv files). Defining 1-N relations ----------------------- +...................... The first thing we are going to do is to let QGIS know about the relations between the layers. This is done in :menuselection:`Project --> Properties...`. @@ -245,7 +237,7 @@ This is possible for layers stored in data providers like PostgreSQL or SpatiaLi .. index:: Feature form, Linked forms, Embedded form Forms for 1-N relations ------------------------ +....................... Now that QGIS knows about the relation, it will be used to improve the forms it generates. As we did not change the default form method (autogenerated), it will just add a new widget in our form. @@ -367,8 +359,8 @@ You will find that many different aggregation functions are available in the for .. index:: Many-to-many relation; Relation .. _many_to_many_relation: -Introducing many-to-many (N-M) relations -======================================== +Many-to-many (N-M) relations +---------------------------- N-M relations are many-to-many relations between two tables. For instance, the ``airports`` and ``airlines`` layers: @@ -532,8 +524,11 @@ A record will automatically be inserted in the ``airports_airlines`` table. .. index:: Polymorphic relation; Relation .. _polymorphic_relation: -Introducing polymorphic relations -================================= +Polymorphic relations +--------------------- + +The purpose +........... Polymorphic relations are special case of 1-N relations, where a single referencing (document) layer contains the features for multiple referenced layers. @@ -561,9 +556,8 @@ in the same table ``documents``. For each feature the referenced layer is stored in the ``referenced_layer`` field and the referenced feature id in the ``referenced_fk`` field. - Defining polymorphic relations ------------------------------- +.............................. First, let QGIS know about the polymorphic relations between the layers. This is done in :menuselection:`Project --> Properties...`. @@ -697,6 +691,8 @@ The example above uses the following database schema: :width: 1.5em .. |openTable| image:: /static/common/mActionOpenTable.png :width: 1.5em +.. |relations| image:: /static/common/relations.png + :width: 1.5em .. |saveEdits| image:: /static/common/mActionSaveEdits.png :width: 1.5em .. |symbologyAdd| image:: /static/common/symbologyAdd.png From d1c053a5855307934c5519df441e30e22bcd6632 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Fri, 11 Aug 2023 07:12:25 +0000 Subject: [PATCH 6/8] Describe buttons of the relations tab --- .../working_with_vector/joins_relations.rst | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index 924771b9743..be8e5babef3 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -127,15 +127,31 @@ Unlike joins that define a one-to-one link between features across two layers, relations help you build interconnections between multiple features across two or more layers. As such, relations are project level settings and are set in :menuselection:`Project --> Properties -->` |relations| :guilabel:`Relations` tab. +From there, you can: -TODO : ADD a screen of the the relations interface +* |symbologyAdd| :guilabel:`Add relation` whose type can be: - .. note:: There is no simple way to edit a relation once it is created yet. - To edit a relation you will have then to remove and create it from scratch. + * :ref:`one to many relation ` + * :ref:`many to many relation ` + * :ref:`polymorphic relation ` that you can add or edit + with the dedicated tools in the action drop-down menu. - .. note:: QGIS is able to discover existing relations from supported databases formats. + .. note:: There is no simple way yet to edit a non-polymorphic relation once it has been created. + To modify a relation you will have to remove and recreate it from scratch. + +* |symbologyAdd| :guilabel:`Discover relations`: QGIS is able to discover existing relations + from supported database formats (PostgreSQL, GeoPackage, ESRI File Geodatabase, ...). This can be a good way to ease the relations definition. +* |symbologyRemove| :guilabel:`Remove relation` + +.. _figure_relations: + +.. figure:: ../introduction/img/project_relations.png + :align: center + + Relations tab +.. TODO: Update and fill the dialog with examples of the different types of relations Once a relation is created in the project properties, it can be used in the layers forms widget Relation Reference /working_with_vector/vector_properties.html#edit-widgets @@ -697,6 +713,8 @@ The example above uses the following database schema: :width: 1.5em .. |symbologyAdd| image:: /static/common/symbologyAdd.png :width: 1.5em +.. |symbologyRemove| image:: /static/common/symbologyRemove.png + :width: 1.5em .. |toggleEditing| image:: /static/common/mActionToggleEditing.png :width: 1.5em .. |unchecked| image:: /static/common/unchecked.png From 51ad93a535069990706c40ac9daf639e44c940c6 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Fri, 11 Aug 2023 21:24:10 +0000 Subject: [PATCH 7/8] Rework and contextualize joins and relations in GIS --- .../working_with_vector/joins_relations.rst | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index be8e5babef3..ac09081bed6 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -1,52 +1,45 @@ .. index:: Joins, Relations .. _sec_joins_relations: -********************************** - Joins and relations -********************************** - -Joins and relations are technical concepts used in databases to get the most out of -data stored in tables by combining their contents. The concept is that -features (rows) of different layers (tables) can belong to each other. One of the -most simple example is the value list where one attribute (foreign key) of a table -is used to create a link to another table which is composed of values.Relations are -usually used to link objects (features) from two layers (tables) together. +******************************************* + Connecting and Editing Data Across Layers +******************************************* .. only:: html .. contents:: :local: +Ability to connect data from different layers is one of the duties of a GIS software. +Such a connection can be based on the spatial relationship between the features, +or on their shared attributes. +QGIS provides tools to handle any of these associations, such as: +* Processing algorithms that can create a new layer as a result of the connection, + namely :ref:`qgisjoinattributesbylocation`, :ref:`qgisjoinbynearest`, + :ref:`qgisjoinattributestable`, ... +* SQL queries to create a new layer from the :ref:`DB Manager ` + or as a :ref:`virtual layer ` +* :ref:`Joins properties ` or :ref:`relations settings ` + that temporarily extend attributes of features in a given layer, + with those of features in another layer based on some matching attribute(s). + Joins and relations are technical concepts borrowed from databases + to get the most out of data stored in tables by combining their contents. + The idea is that features (rows) of different layers (tables) can belong to each other. + The links between the features can be of one-to-one type (joins) or one/many to many (relations). -QGIS allows you to create and manage joins between tables (spatial or non spatial). -This is done on the layer level (properties). Joins enable you to define -links between an attribute of a table and a value stored in another table. .. index:: Joins, Foreign key .. _`sec_joins`: -The most simple example is not even a real join but the possibility offered by QGIS -to set a value list directly in the attribute form using the Value Map widget -(TODO : ADD link to /working_with_vector/vector_properties.html#edit-widgets) -to define mapping values manually or using a CSV or layer import. Joining features between two layers ==================================== -The second example is to use the Value Relation widget -(TODO : ADD link to /working_with_vector/vector_properties.html#edit-widgets) -to define a relation between an attribute and an other attribute contained in another layer. **Joins** allow you to associate features of the current layer to features from another loaded vector layer. Whether they are spatially enabled and their geometry type does not matter. The join is based on an attribute that is shared by the layers, in a one-to-one relationship. -The third example is to use the Joins tab -(TODO : add link /working_with_vector/vector_properties.html#joins-properties) -to associate features of the current layer -to features from another loaded layer. The join is based on an attribute -that is shared by the layers. This enable to add one or more attribute from a table -to the other. To create a join on a layer (identified below as ``target layer``): @@ -152,10 +145,6 @@ From there, you can: Relations tab .. TODO: Update and fill the dialog with examples of the different types of relations -Once a relation is created in the project properties, it can be used in the -layers forms widget Relation Reference -/working_with_vector/vector_properties.html#edit-widgets -or used in the field expression calculator to design some powerful queries and features. .. _one_to_many_relation: From 8fba947e6f24384149d8e5567a7a5bb4c2ad7062 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Tue, 17 Oct 2023 03:21:33 +0200 Subject: [PATCH 8/8] Apply suggestions from review Co-authored-by: Denis Rouzaud --- .../working_with_vector/joins_relations.rst | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/user_manual/working_with_vector/joins_relations.rst b/docs/user_manual/working_with_vector/joins_relations.rst index ac09081bed6..16799ff7e8d 100644 --- a/docs/user_manual/working_with_vector/joins_relations.rst +++ b/docs/user_manual/working_with_vector/joins_relations.rst @@ -26,8 +26,8 @@ QGIS provides tools to handle any of these associations, such as: Joins and relations are technical concepts borrowed from databases to get the most out of data stored in tables by combining their contents. - The idea is that features (rows) of different layers (tables) can belong to each other. - The links between the features can be of one-to-one type (joins) or one/many to many (relations). + The idea is that features (rows) of different layers (tables) can be associated to each other. + The number of rows which are matching each other can be of any value (zero, one, many). .. index:: Joins, Foreign key @@ -36,9 +36,9 @@ QGIS provides tools to handle any of these associations, such as: Joining features between two layers ==================================== -**Joins** allow you to associate features of the current layer +**Joins** in QGIS allow you to associate features of the current layer to features from another loaded vector layer. -Whether they are spatially enabled and their geometry type does not matter. +Whether they are spatially enabled and the type of geometry do not matter. The join is based on an attribute that is shared by the layers, in a one-to-one relationship. To create a join on a layer (identified below as ``target layer``): @@ -61,7 +61,7 @@ To create a join on a layer (identified below as ``target layer``): Join an attribute table to an existing vector layer The steps above will create a join, -where **ALL** the attributes of the first matching feature in the join layer +where **ALL** the attributes of the **first matching feature** in the join layer is added to the target layer's feature. The following logic is used to pair features during a join process: @@ -103,12 +103,6 @@ QGIS provides some more options to tweak the join: * |unchecked| :guilabel:`Custom field name prefix` for joined fields, in order to avoid name collision -QGIS currently has support for joining non-spatial table formats supported by GDAL -(e.g., CSV, DBF and Excel), delimited text and the PostgreSQL providers. - -.. is the above still true? No more supported formats (oracle, mssql, ...)??? - - .. index:: Relations, Foreign key .. _vector_relations: @@ -130,7 +124,8 @@ From there, you can: with the dedicated tools in the action drop-down menu. .. note:: There is no simple way yet to edit a non-polymorphic relation once it has been created. - To modify a relation you will have to remove and recreate it from scratch. + Only the name can be edited with a double-click. + For any other parameters of such a relation you will have to remove and recreate it. * |symbologyAdd| :guilabel:`Discover relations`: QGIS is able to discover existing relations from supported database formats (PostgreSQL, GeoPackage, ESRI File Geodatabase, ...).