Skip to content

Commit

Permalink
Update database-schema.adoc, corrected link 'SuiteCRM Database Schema'
Browse files Browse the repository at this point in the history
  • Loading branch information
srcengine authored and serhiisamko091184 committed Jul 23, 2024
1 parent 5887fe0 commit 8913a21
Showing 1 changed file with 29 additions and 29 deletions.
58 changes: 29 additions & 29 deletions content/developer/database-schema.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ weight: 195

== SchemaSpy tables and diagrams

To learn about our database structure, with its tables and relationships,
please visit the link:++https://schema--suitecrm-docs.netlify.com/schema++[SuiteCRM Database Schema^],
To learn about our database structure, with its tables and relationships,
please visit the link:++https://schema--suitecrm-docs.netlify.app/schema++[SuiteCRM Database Schema^],
generated with SchemaSpy.

image:schemaspy.png[link="https://schema--suitecrm-docs.netlify.com/schema", SchemaSpy screenshot, window="_blank"]
image::schemaspy.png[link="https://schema--suitecrm-docs.netlify.app/schema", SchemaSpy screenshot, window="_blank"]

== General principles and sample SQL queries

{{% notice warning %}}
Some of the queries provided below delete data from your database. Use at your own risk, and be sure
to create full backups before trying them. A single mistaken SQL query can produce irreparable
to create full backups before trying them. A single mistaken SQL query can produce irreparable
damage to your database.
{{% /notice %}}

=== Unique identifiers

SuiteCRM uses UUID's for its unique identifiers. They look like this: `46c35607-bcad-c7f1-1745-558d6b858b27`.
SuiteCRM uses UUID's for its unique identifiers. They look like this: `46c35607-bcad-c7f1-1745-558d6b858b27`.
They can be generated in SQL and inserted into other queries as a sub-select:

[source,sql]
Expand All @@ -37,19 +37,19 @@ by allowing previous numbering schemes to be maintained.

=== Custom Fields

Custom fields get saved in tables with the same name as the module they are defined in, but with an
appended suffix `_cstm`.
Custom fields get saved in tables with the same name as the module they are defined in, but with an
appended suffix `_cstm`.

Each custom field will have the name you entered for it in Studio, with a suffix `_c`.

Here is a sample query to join a module's table with some custom fields (in this case, a field called
Here is a sample query to join a module's table with some custom fields (in this case, a field called
**age** when created in Studio):

[source,sql]
----
SELECT first_name, last_name, contacts_cstm.age_c
SELECT first_name, last_name, contacts_cstm.age_c
FROM `contacts`
LEFT JOIN contacts_cstm
LEFT JOIN contacts_cstm
ON contacts.id = contacts_cstm.id_c
----

Expand All @@ -59,8 +59,8 @@ exists in the custom table:
[source,sql]
----
SELECT * -- DELETE ChildTable
FROM contacts_cstm ChildTable
LEFT JOIN contacts ParentTable
FROM contacts_cstm ChildTable
LEFT JOIN contacts ParentTable
ON ChildTable.id_c = ParentTable.id
WHERE ParentTable.id IS NULL
----
Expand All @@ -70,14 +70,14 @@ it will delete those rows. Please read the warning above and decide responsibly.

=== Relationships

SuiteCRM does not rely on the database engine to enforce relationships (foreign key constraints, etc).
SuiteCRM does not rely on the database engine to enforce relationships (foreign key constraints, etc).
All these things are handled at application level in our own PHP code.

In general, SuiteCRM also does not do any cascaded updates or cascaded deletes, there are only a few
In general, SuiteCRM also does not do any cascaded updates or cascaded deletes, there are only a few
exceptions for some particular cases. This means that you might need some periodic database clean-up.
There is a "Prune database on the 1st of month" scheduled job that handles some of these tasks,
but you need to evaluate your own case in order to decide on the appropriate house-cleaning tasks.
There is no "one-size-fits-all" solution for this, so each implementation should take the necessary
There is a "Prune database on the 1st of month" scheduled job that handles some of these tasks,
but you need to evaluate your own case in order to decide on the appropriate house-cleaning tasks.
There is no "one-size-fits-all" solution for this, so each implementation should take the necessary
steps for its own case.

There is a table called `relationships` which contains metadata information retrieved from the **vardefs**.
Expand All @@ -88,7 +88,7 @@ A few sample queries should suffice to give you an idea of how SuiteCRM tables t

. The query to get data from a **custom field** that was given above;
+
. Traversing a **Flex Relate** field where several connected record types are allowed. The `parent_type`
. Traversing a **Flex Relate** field where several connected record types are allowed. The `parent_type`
field contains the name of the related module, while the `parent_id` is a foreign key into that module's table:
+
[source,sql]
Expand All @@ -97,12 +97,12 @@ SELECT accounts.name, calls.name, calls.status
FROM accounts
INNER JOIN calls ON
calls.parent_type = 'Accounts' AND
calls.parent_id = accounts.id AND
calls.parent_id = accounts.id AND
calls.deleted = 0
WHERE accounts.deleted = 0
----
+
. A query to traverse a **many-to-many relationship** using a middle table. In this example, a list of
. A query to traverse a **many-to-many relationship** using a middle table. In this example, a list of
account names and linked contacts:
+
image:schema.png[Schema]
Expand All @@ -112,7 +112,7 @@ image:schema.png[Schema]
SELECT accounts.name, contacts.first_name, contacts.last_name
FROM accounts
INNER JOIN accounts_contacts
ON (accounts.id = accounts_contacts.account_id AND accounts_contacts.deleted = 0)
ON (accounts.id = accounts_contacts.account_id AND accounts_contacts.deleted = 0)
INNER JOIN contacts
ON (contacts.id = accounts_contacts.contact_id AND contacts.deleted = 0)
WHERE accounts.deleted = 0
Expand All @@ -139,33 +139,33 @@ SELECT users.user_name,

==== Cleaning up Relationships to deleted records

When you delete a record from a module, in many cases SuiteCRM does not delete all the associated records,
because it is impossible to decide which should or should not be removed without knowing the specifics of each
When you delete a record from a module, in many cases SuiteCRM does not delete all the associated records,
because it is impossible to decide which should or should not be removed without knowing the specifics of each
business. Not deleting is _generically_ the sensible, conservative approach. But if you decide in your
case you need to remove some left-overs from previously existing records, then the following should help you.

Here is a sample query to look for orphaned records, in this case security groups entries referring
Here is a sample query to look for orphaned records, in this case security groups entries referring
to missing records:

[source,sql]
----
SELECT record_id, module, s.deleted, c.last_name, c.deleted
FROM securitygroups_records s
LEFT JOIN contacts c
FROM securitygroups_records s
LEFT JOIN contacts c
ON s.record_id = c.id
WHERE c.id IS NULL AND
s.module='Contacts'
s.module='Contacts'
----

This query can easily be turned into a DELETE in order to remove these records.

You might also make a simpler delete of rows where `deleted='1'`, where the relationship itself was deleted,
You might also make a simpler delete of rows where `deleted='1'`, where the relationship itself was deleted,
even if the `record_id` still exists:

[source,sql]
----
SELECT record_id, module, deleted
FROM securitygroups_records
FROM securitygroups_records
WHERE module='Contacts' AND deleted='1'
----

Expand Down

0 comments on commit 8913a21

Please sign in to comment.