Mira Jill Yumul
05/12/2026, 3:39 AMvw_expense. The result now shows all matters linked to the specific firm, and have existing expenses.
Please let me know if additional information is needed here 🙏 Thanks in advance
Query:
-- dsId: 8ad48ef0-ece5-4c7d-8fae-a86326beb1f0
SELECT `a_matter_code` AS `l_matter_code`, `a_matter_title` AS `l_matter_title`, `a_business_contact_company_name` AS `l_business_contact_company_name`, `a_individual_contact_full_name` AS `l_individual_contact_full_name`, `a_user_name` AS `l_user_name`, `m_be761a7f9e729d64f471fc11c72446db` AS `m_1`
FROM (SELECT `vw_business_contact`.`business_contact_company_name` AS `a_business_contact_company_name`, `vw_individual_contact`.`individual_contact_full_name` AS `a_individual_contact_full_name`, `vw_matter`.`matter_code` AS `a_matter_code`, `vw_matter`.`matter_title` AS `a_matter_title`, `vw_user`.`user_name` AS `a_user_name`, COUNT(DISTINCT `vw_matter`.`matter_id`) AS `m_be761a7f9e729d64f471fc11c72446db`, TRUE AS `def_m_be761a7f9e729d64f471fc11c72446db`
FROM `fountain_court`.`vw_expense`
INNER JOIN `fountain_court`.`vw_matter` ON `vw_expense`.`matter_id` = `vw_matter`.`matter_id`
INNER JOIN `fountain_court`.`vw_user` ON `vw_expense`.`user_id` = `vw_user`.`user_id`
INNER JOIN `fountain_court`.`vw_matter_contact` ON `vw_expense`.`matter_id` = `vw_matter_contact`.`matter_id`
INNER JOIN `fountain_court`.`vw_business_contact` ON `vw_matter`.`matter_firm_id` = `vw_business_contact`.`business_contact_id`
INNER JOIN `fountain_court`.`vw_individual_contact` ON `vw_matter_contact`.`contact_id` = `vw_individual_contact`.`individual_contact_id`
WHERE `vw_matter`.`matter_is_draft` = 'false'
GROUP BY `vw_matter`.`matter_code`, `vw_matter`.`matter_title`, `vw_user`.`user_name`, `vw_business_contact`.`business_contact_company_name`, `vw_individual_contact`.`individual_contact_full_name`) AS `t2`
WHERE `t2`.`def_m_be761a7f9e729d64f471fc11c72446db` AND `t2`.`a_business_contact_company_name` = 'Winston Taylor International LLP';kapa.ai
05/12/2026, 3:39 AMvw_expense — likely because vw_expense is the fact/lowest-grain dataset that has foreign keys linking to matters, users, and (via vw_matter_contact) to individual contacts. Without Individual Contact Full Name, GoodData could use a different path, but adding it forces the planner to route through vw_expense as the common base. [Connection points]
This also explains why your results are now filtered to matters with existing expenses — because vw_expense is the base table, the INNER JOIN to vw_matter means only matters that have at least one expense row are returned.
What You Can Do To avoid routing through vw_expense, you have a few options:
1. Eliminate alternate paths in your LDM so that only the desired path (not through vw_expense) remains between Individual Contacts and the other datasets. [Alternate paths]
2. Create a bridge/SQL dataset at the correct grain — for example, a view keyed by matter_id that already joins in individual contact fields directly, and connect it to the Matters dataset. This avoids dependence on vw_expense as the connecting dataset. [Bridge dataset pattern]
3. Review the relationship directions (arrows) in your LDM — the engine follows the shortest valid path between datasets based on arrow directions. If the only valid path between Individual Contacts and Matters currently goes through vw_expense, you need to introduce a direct or alternative connection that does not require it. [LDM relationships]
Tip for Debugging You can append /debug to the end of the Analyse URL (replacing /edit) to download a debug file containing the exact SQL query being generated. This can help you trace which join path is being used and why. [Debug tip]
In summary, the root cause is that vw_expense is the fact dataset that GoodData identifies as the lowest-grain common connector for all the objects in your insight once Individual Contact Full Name is added. Redesigning the LDM to provide a direct path between Individual Contacts and Matters (without going through vw_expense) is the recommended fix. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups.
👀 Our Support team monitors all messages and will jump in if needed.Mira Jill Yumul
05/12/2026, 3:42 AMJulius Kos
05/12/2026, 7:36 AMkapa.ai
05/12/2026, 8:27 AMvw_expense as the driving dataset, which then filters results to only matters that have existing expenses via the INNER JOIN.
This is a known LDM design issue, not a bug in your data. The root cause is that the only valid join path GoodData can find to connect Individual Contacts to the rest of your model goes through vw_expense. [Connection points]
To achieve your expected behavior (all matters visible regardless of whether Individual Contact is added), you need to provide GoodData with a join path to Individual Contacts that does not go through vw_expense. The recommended approaches are:
1. Create a bridge/SQL dataset at matter grain — a view keyed by matter_id that directly joins in individual contact fields, connected to the Matters dataset. This gives GoodData a direct path that doesn't require vw_expense.
2. Eliminate alternate paths in your LDM so the only valid path between Individual Contacts and Matters is the direct one (not through vw_expense).
3. Review arrow directions in your LDM to ensure the relationship between Individual Contacts and Matters is navigable without routing through the expense dataset. [LDM relationships]
Without one of these LDM changes, GoodData will continue to route through vw_expense whenever Individual Contact Full Name is included, causing the unintended filtering of results. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups.
👀 Our Support team monitors all messages and will jump in if needed.Julius Kos
05/12/2026, 8:31 AM/debug SQLs for both the single-bridge and combined-bridge variants, and that's what let us pinpoint exactly where the behavior stems. With either bridge used alone, the planner correctly anchors on vw_matter_barrister or vw_matter_contact. The moment both M:N bridges are combined in a single insight, the planner switches to vw_expense as the FROM clause — and since that view uses `INNER JOIN`s throughout, results collapse to only matters that have at least one expense row.
The reason vw_expense gets picked is that your Expenses dataset has direct FK references to both Matters and Users. When the optimizer needs to combine two bridges, it finds it "cheaper" to anchor on that single fact table rather than chain two separate M:N bridges off Matters.
As a workaround you can use right now, split it into two insights on the same dashboard — one with Matter Code, Matter Title, Firm, and Barrister, and another with Matter Code, Matter Title, Firm, and Individual Contact Full Name. Apply the Firm = Winston Taylor International LLP filter at the dashboard level so it propagates to both, and cross-reference via Matter Code. Both queries will anchor correctly on their respective bridges with no vw_expense involvement.
The longer-term fix would need to happen in the LDM, specifically the Expenses → Users reference. If Expenses.user_id represents something semantically distinct from "Barrister" (e.g. the user who logged the expense), modelling it as a separate role/dataset would remove that shortcut and allow a combined insight to work cleanly.
We will gladly give you some hints or direct you the way how this could be resolved. However, please note that similar kind of LDM change is outside the scope of what our Support team handles, but our Professional Services team would be well-placed to help with it. If you're interested, feel free to reach out to your account owner Thiago Alves (thiago.alves@gooddata.com) and he can get you connected.Julius Kos
05/12/2026, 8:51 AMMatter Barristers bridge (simplest: SUM(Barrister Due Days), since that fact lives in that dataset), the planner is forced to keep vw_matter_barrister in the query and the vw_expense shortcut disappears. Verified in /debug — FROM becomes vw_matter_contact joined directly to vw_matter_barrister and vw_matter, and the full list of matters for the firm comes back instead of just those with expenses.
Trade-off is an extra Barrister Due Days column.Julius Kos
05/12/2026, 8:53 AMMira Jill Yumul
05/12/2026, 11:18 PMExpenses → Users reference, as Expenses.user_id represents the "Barrister" linked to that expense. We may have visualizations where we filter/group the expenses by barristerMira Jill Yumul
05/17/2026, 11:24 PMJulius Kos
05/18/2026, 4:48 PMExpenses → Users relationship, to avoid unintended planner shortcuts. This type of redesign would need to be done from your end as you are better familiar with your analytics and specific reporting needs and this is unfortunately outside the scope of Support and would be better handled by our Professional Services team, who can assess the impact on your existing model and dashboards in detail. As was mentioned - If you’re interested, your account owner Thiago can help arrange this. Thank you for your understanding.Mira Jill Yumul
05/18/2026, 11:33 PM