This is an automated email from the ASF dual-hosted git repository. elizabeth pushed a commit to branch fix/time-offset-totals-join in repository https://gitbox.apache.org/repos/asf/superset.git
commit 40f8d873b20157f02a8e921c573301a53bd85b4a Author: Elizabeth Thompson <[email protected]> AuthorDate: Tue Jan 13 17:35:36 2026 -0800 fix(table chart): time comparison totals returning null When a table chart has `show_totals=true` and `time_offsets` enabled, the totals row was showing null for the time comparison column. This happened because the totals query has `columns=[]` (no dimension columns), and `_determine_join_keys` was trying to create a join column from the first column (a numeric metric value) instead of using the `__temp_join_key__` fallback mechanism. The fix checks if there are no join keys AND the first column is not a datetime, and in that case returns empty join keys which triggers the correct fallback join behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --- superset/models/helpers.py | 10 +++++++++ tests/unit_tests/common/test_time_shifts.py | 33 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/superset/models/helpers.py b/superset/models/helpers.py index a4fb9e3fea..da37869bc3 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -1800,6 +1800,16 @@ class ExploreMixin: # pylint: disable=too-many-public-methods ) -> tuple[pd.DataFrame, list[str]]: """Determine appropriate join keys and modify DataFrames if needed.""" if time_grain and not is_date_range_offset: + # When there are no join keys (e.g., totals query with columns=[]), + # check if the first column is a datetime before attempting to use it + # for join column generation. If it's not a datetime (e.g., only metric + # columns exist), fall back to empty join keys which will trigger the + # __temp_join_key__ mechanism in _perform_join. + if not join_keys and len(df.columns) > 0: + first_col_dtype = df.iloc[:, 0].dtype + if not pd.api.types.is_datetime64_any_dtype(first_col_dtype): + return offset_df, [] + column_name = OFFSET_JOIN_COLUMN_SUFFIX + offset # Add offset join columns for relative time offsets diff --git a/tests/unit_tests/common/test_time_shifts.py b/tests/unit_tests/common/test_time_shifts.py index 08b6478c48..09984a1922 100644 --- a/tests/unit_tests/common/test_time_shifts.py +++ b/tests/unit_tests/common/test_time_shifts.py @@ -209,3 +209,36 @@ def test_join_offset_dfs_with_month_granularity(): ) assert_frame_equal(expected, result) + + +def test_join_offset_dfs_totals_query_no_dimensions(): + """ + Test time offset join for totals query with no dimension columns. + + This simulates a table chart totals query where: + - columns=[] (no dimensions, only metrics) + - time_offsets=["1 month ago"] + - The dataframes only contain metric columns (no datetime column) + + The join should use the __temp_join_key__ fallback mechanism + to properly join the offset data. + """ + # Main totals query result - only has metric column, no datetime + df = DataFrame({"Total Cost": [54211.76]}) + + # Offset query result - renamed metric column + offset_df = DataFrame({"Total Cost__1 month ago": [48000.50]}) + + offset_dfs = {"1 month ago": offset_df} + time_grain = "P1D" # Daily grain from extras + join_keys = [] # No dimension columns for totals query + + expected = DataFrame( + {"Total Cost": [54211.76], "Total Cost__1 month ago": [48000.50]} + ) + + result = query_context_processor.join_offset_dfs( + df, offset_dfs, time_grain, join_keys + ) + + assert_frame_equal(expected, result)
