My solution is to abandon SQL-CE and make a memory connection on the client.
The only option that works is the latter, and the performance on real data was horrific due to a full scan of both tables.
CREATE TABLE f_normalised_report_data ( level1_id INT, level2_id INT, level3_id INT, level4_id INT, level5_id INT, level6_id INT, metric_id INT, value MONEY, PRIMARY KEY ( level1_id, level2_id, level3_id, level4_id, level5_id, level6_id, metric_id ) ) ; CREATE TABLE f_normalised_report_hierarchy ( level1_id INT, level2_id INT, level3_id INT, level4_id INT, level5_id INT, level6_id INT, PRIMARY KEY ( level1_id, level2_id, level3_id, level4_id, level5_id, level6_id ) ) ; INSERT INTO f_normalised_report_hierarchy SELECT 1, 2, 3, 4, 5, 6; INSERT INTO f_normalised_report_hierarchy SELECT 1, 2, 3, 4, 5, 7; INSERT INTO f_normalised_report_data SELECT 1, 2, 3, 0, 5, 6, 22, 999; INSERT INTO f_normalised_report_data SELECT 1, 2, 3, 0, 5, 7, 22, 911; SELECT * FROM f_normalised_report_hierarchy AS [map] LEFT JOIN f_normalised_report_data AS [data] ON ([data].level1_id = [map].level1_id OR [data].level1_id = 0) AND ([data].level2_id = [map].level2_id OR [data].level2_id = 0) AND ([data].level3_id = [map].level3_id OR [data].level3_id = 0) AND ([data].level4_id = [map].level4_id OR [data].level4_id = 0) AND ([data].level5_id = [map].level5_id OR [data].level5_id = 0) AND ([data].level6_id = [map].level6_id OR [data].level6_id = 0) ;