Skip to main content

Hi everyone,

I'm facing an issue with how Celonis handles many-to-many (N:N) relationships. It seems like Celonis treats these relationships as 1:N → 1:N instead of supporting 0:N → 0:N, which leads to missing data when filtering.

Example Issue:

I have a many-to-many relationship between contracts and assets, modeled with an intermediate table:

Contract Asset
C1 A2
C2 A1
C3 NULL
C4 NULL
NULL A3
NULL A4

The issue occurs when I apply a filter like "Asset ≠ A4". Instead of just removing A4, I also lose contracts C3 and C4, which should still be visible since they are not linked to any asset.

My Understanding of the Issue:

  • Celonis seems to implicitly treat N:N relationships as 1:N → 1:N, enforcing a strict link between contracts and assets.
  • It does not seem to support a true N:N model, where both sides can have optional (0:N) relationships.

Question:

Has anyone faced this issue before?
Is there a recommended modeling approach to ensure that filtering on assets does not remove unrelated contracts?

Thanks in advance! 😊

Hi ​@maxime.psbpm,

Indeed, Celonis does not natively support 0:N → 0:N modeling, Celonis treats N:N as 1:N → 1:N, which can cause unintended data loss when filtering. This is because the default filtering logic in Celonis are INNER JOINS, where only matching records remain.

So in your case, This means contracts that do not have a linked asset get unintentionally filtered out.

To avoid losing unrelated contracts, in the past I modeled the assets in a separate table instead of relying solely on an intermediate table.

Your asset table would be something like this.


SELECT DISTINCT Asset 
FROM CONTRACT_ASSET 
WHERE Asset IS NOT NULL;


This table would then contain only the assets, without the link to contracts.


And then you would have to Modify your contract_asset table to ensure there are only valid links.

 

This ensures:

  • Only actual contract-asset links exist in the join table
  • Contracts without assets are handled separately.

In the end, you can apply the filtering on assets, not contract_assets. this ensures C3 and C4 aremain in the dataset because we didn’t filter them out through Celonis’ default INNER JOIN.

 

This is pretty hard to explain textually, apologies. If you need some more help, let me know.


Hi ​@Sverre Klein ,

Thank you so much for your detailed response! I really appreciate you taking the time to explain the logic behind Celonis' default filtering behavior and how it impacts many-to-many relationships. It definitely clarifies why contracts without linked assets are unintentionally filtered out.

However, I believe I may not have fully grasped the proposed solution. I have tried handling assets separately and vice versa, but unfortunately, I haven't been able to achieve the desired result. In fact, I initially added the NULL rows in the intermediary table as an attempt to address the issue, but even when keeping only the base rows, the problem persists.

To make sure we're on the same page, here’s a simplified example of my current data model, which still exhibits the filtering issue:

 

Table A (Assets):

Number Description
A1 Asset with contract
A2 Asset with contract
A3 Asset without contract
A4 Asset without contract

 

Table B (Intermediary Table - Contract-Asset Link):

Asset Contract
A1 C1
A1 C2
A2 C1
A2 C2

 

Table C (Contracts):

Contract Description
C1 Contract with asset
C2 Contract with asset
C3 Contract without asset
C4 Contract without asset

 

Current Modeling:

  • Table A (1 ⟷ N) Table B (N ⟷ 1) Table C

As expected, when applying filters on assets in Studio (e.g., selecting one or more asset values), all contracts without linked assets (C3, C4) are also excluded, even though they should remain visible.

Would you be able to suggest a concrete solution using this model format? If we don't manage to resolve it this way, I’d be happy to connect directly if you think you could help further!

I really appreciate your time and insights—thank you again! 😊

 


No worries ​@maxime.psbpm, let’s see if we can solve this.

We need to implement a FULL OUTER JOIN like behavior for your problem I think. This is to ensure we can decouple the dependency between filtering on assets and filtering on contracts.

I have looking back in my old SQL code how I did it, so let’s see if this also works for you. Mind that I am using external scripting for SQL, so you might have to see if the code works inside Celonis SQL.

First, we have to explictly include contracts that do not have assets in Table B.
 

CREATE TABLE CONTRACT_ASSET AS 
SELECT Asset, Contract FROM Table_B  -- Existing Contract-Asset pairs
UNION ALL
SELECT NULL AS Asset, Contract FROM Table_C WHERE Contract NOT IN (SELECT DISTINCT Contract FROM Table_B);

This ensures that C3 and C4 remain in the dataset from Table B. Mind that we replace table B for CONTRACT_ASSET here.

Second, we need contracts without assets as well to be preserved in Table A.

SELECT DISTINCT Contract, Asset
FROM CONTRACT_ASSET
WHERE Asset IS NULL OR Asset IN ('A1', 'A2'); →  (example filter)

Your model would then be:

  • Link Table A (Assets) → CONTRACT_ASSET on asset
  • Link Table C (Contracts) → CONTRACT_ASSET on contract

You will have to play around with this code to have it work for you. Hopefully this will lead to your intended behavior.


Thank you very much again! I fully understand the first part where we add assets without contracts and contracts without assets into the CONTRACT_ASSET table, but it didn’t work as expected. I had actually tried this before my first message in the conversation, but it didn’t work, and I was surprised.

However, I don’t really understand the second part with the query you proposed for Table A. Since (unless I’m mistaken) in Celonis, queries are only used to create tables and not to perform the JOINs, which are managed directly in the data model, it would be much easier for me if you could send me the three tables with the example I provided (Table A, Table B, and Table C with the same values and columns).

Also, I don’t think so, but just to confirm—does writing these queries modify the underlying data model?


@Sverre Klein just tagging you here in case you didn't get the notification. :)


Reply