library(tidyverse)
library(readxl)
library(glue)
library(janitor)
path <- "Power Query/300-399/347/PQ_Challenge_347 - Table Decomposition.xlsx"
input1 <- read_excel(path, range = "A1:F6")
input2 <- read_excel(path, range = "A8:B11")
test <- read_excel(path, range = "I1:P20")
cartesian_product <- crossing(
input1 %>% mutate(ID = glue("ID{row_number()}") %>% as.character()),
input2
)
result = cartesian_product %>%
mutate(
`Activity ID` = glue("{`Sub Table`}_{ID}") %>% as.character(),
Quantity = Quantity * `%`,
`Total Weight` = Quantity * `Unit Weight`
) %>%
select(
`Sub Table`,
`Activity ID`,
`Activity Name`,
Unit,
Quantity,
`Unit Weight`,
`Total Weight`,
Chainage,
`Resource Name`
) %>%
arrange(`Activity ID`)
subs = result %>%
summarise(
`Total Weight` = sum(`Total Weight`),
.by = `Sub Table`
) %>%
mutate(
`Sub Table`,
`Activity ID` = "TOTAL",
`Activity Name` = NA,
Unit = NA,
Quantity = NA,
`Unit Weight` = NA,
`Total Weight`,
Chainage = NA,
`Resource Name` = NA
)
total = result %>%
summarise(
`Total Weight` = sum(`Total Weight`)
) %>%
mutate(
Chainage = NA,
`Resource Name` = NA,
Unit = NA,
Quantity = NA,
`Unit Weight` = NA,
`Activity ID` = "GRAND TOTAL",
`Activity Name` = NA,
.data = .,
`Total Weight`,
`Sub Table` = NA
)
final_result = bind_rows(
result %>% filter(`Sub Table` == "Subtable-1"),
subs %>% filter(`Sub Table` == "Subtable-1"),
result %>% filter(`Sub Table` == "Subtable-2"),
subs %>% filter(`Sub Table` == "Subtable-2"),
result %>% filter(`Sub Table` == "Subtable-3"),
subs %>% filter(`Sub Table` == "Subtable-3"),
total
) %>%
select(-`Sub Table`)
all.equal(final_result, test, check.attributes = FALSE)Excel BI - PowerQuery Challenge 347
excel-challenges
power-query
Activity Name Unit Quantity Unit Weight Chainage Resource Name

Challenge Description
Activity Name Unit Quantity Unit Weight Chainage Resource Name
Solutions
Logic:
Reads the workbook range needed for the challenge
Aggregates or ranks values at the relevant grouping level
Builds helper columns that drive the final output
Strengths:
- The R solution stays close to the workbook logic and keeps the transformation compact.
Areas for Improvement:
- The code assumes the workbook layout and selected ranges remain stable.
Gem:
- The best part of the solution is choosing the right intermediate shape before formatting the final output.
import pandas as pd
import numpy as np
path = "Power Query/300-399/347/PQ_Challenge_347 - Table Decomposition.xlsx"
input1 = pd.read_excel(path, sheet_name=0, usecols="A:F", nrows=5)
input2 = pd.read_excel(path, sheet_name=0, usecols="A:B", skiprows=7, nrows=4)
test = pd.read_excel(path, sheet_name=0, usecols="I:P", nrows=20).rename(columns=lambda col: col.replace(".1", ""))
input1["ID"] = ["ID" + str(i) for i in range(1, len(input1) + 1)]
cart = input1.merge(input2, how="cross")
cart["Activity ID"] = cart["Sub Table"] + "_" + cart["ID"]
cart["Quantity"] = cart["Quantity"] * cart["%"]
cart["Total Weight"] = cart["Quantity"] * cart["Unit Weight"]
cols = [
"Sub Table", "Activity ID", "Activity Name", "Unit", "Quantity",
"Unit Weight", "Total Weight", "Chainage", "Resource Name"
]
result = cart[cols].sort_values("Activity ID")
subs = result.groupby("Sub Table", as_index=False)["Total Weight"].sum()
subs["Activity ID"] = "TOTAL"
for col in ["Activity Name", "Unit", "Quantity", "Unit Weight", "Chainage", "Resource Name"]:
subs[col] = None
subs = subs[cols]
total = pd.DataFrame({
"Activity ID": ["GRAND TOTAL"],
"Total Weight": [result["Total Weight"].sum()],
**{col: [None] for col in cols if col not in ["Activity ID", "Total Weight"]}
})[cols]
final = pd.concat([
result[result["Sub Table"] == "Subtable-1"],
subs[subs["Sub Table"] == "Subtable-1"],
result[result["Sub Table"] == "Subtable-2"],
subs[subs["Sub Table"] == "Subtable-2"],
result[result["Sub Table"] == "Subtable-3"],
subs[subs["Sub Table"] == "Subtable-3"],
total
], ignore_index=True)[cols[1:]]
final = final.replace({np.nan: "", None: ""})
test = test.replace({np.nan: "", None: ""})
print(test)
print(final)Logic:
Reads the workbook range needed for the challenge
Aggregates or ranks values at the relevant grouping level
Applies the rule iteratively until the output is complete
Strengths:
- The Python version follows the same workbook rule in a direct pandas-oriented implementation.
Areas for Improvement:
- As with the R version, any workbook layout change would require small adjustments.
Gem:
- The implementation stays close to the source challenge instead of adding unnecessary abstraction.
Difficulty Level
This task is easy to moderate:
- The transformation rule is readable, but the final layout still requires a careful implementation.