0

I'm looking for help in how to structure a MS Access SQL query on multiple tables and summarize the results grouped by Project and the sum of the dollar amounts for different types of financial transactions.

The Project table contains meta data about a Project. The Actuals, Budget, and Forecast tables are records of actual and/or planned financial transactions against the Project.

The tables and fields (simplified significantly for this post) are as follows:

Project
--------------
project_id
project_name
project_manager

Budget
--------------
entry_date
project_id
amount

Actuals
--------------
entry_date
project_id
amount

Forecast
--------------
entry_date
project_id
amount

SQL attempt:

SELECT
    p.[project_id],
    SUM(b.[amount]) AS budget_amount,
    SUM(a.[amount]) AS actual_amount,
    SUM(f.[amount]) AS forecast_amount
FROM
    Project AS p,
    Budget AS b,
    Actuals AS a,
    Forecast AS f
WHERE
    p.[project_id] = b.[project_id]
    AND b.[project_id] = a.[project_id]
    AND a.[project_id] = f.[project_id]
GROUP BY
    p.[project_id];

Desired Result:

project_id  budget_amount   actual_amount   forecast_amount
2021-001    $2,000.00   $2,900.00   $2,400.00
2021-002    $3,000.00   $3,500.00   $5,000.00

Actual Result:

project_id  budget_amount   actual_amount   forecast_amount
2021-001    $12,000.00  $17,400.00  $9,600.00
2021-002    $18,000.00  $21,000.00  $20,000.00

Sample Data:

Project

project_id  project_name    project_manager
2021-001    First Project of 2021   Jack Black
2021-002    Second Project of 2021  James Dean

Actuals

entry_date  project_id  amount
1/9/2021    2021-001    $1,300.00
1/23/2021   2021-001    $1,600.00
1/9/2021    2021-002    $1,500.00
1/23/2021   2021-002    $2,000.00

Budget

entry_date  project_id  amount
1/9/2021    2021-001    $1,000.00
1/23/2021   2021-001    $1,000.00
1/9/2021    2021-002    $1,500.00
1/23/2021   2021-002    $1,500.00

Forecast

entry_date  project_id  amount
1/9/2021    2021-001    $900.00
1/23/2021   2021-001    $1,000.00
2/6/2021    2021-001    $500.00
1/9/2021    2021-002    $1,500.00
1/23/2021   2021-002    $3,000.00
2/6/2021    2021-002    $500.00
tunneling
  • 527
  • 6
  • 21
  • 1
    Please don't [delete & repost questions](https://stackoverflow.com/q/65972869/3404097), edit them. PS We can't cut & paste & run this. Please don't dump wrong code, where is the 1st subexpression that doesn't return what you expect & why? Etc per my comments on the duplicate & the site documentation. [mre] [help] [meta] [meta.se] – philipxy Jan 31 '21 at 00:14
  • 1
    This is presumably a common error where people want some joins, each possibly involving a different key, of some subqueries, each possibly involving join and/or aggregation, but they erroneously try to do all the joining then all the aggregating or to aggregate over previous aggregations. Write separate sums over appropriate rows and/or sum a case statement picking rows; join on common unique column sets. [Strange duplicate behavior from GROUP_CONCAT of two LEFT JOINs of GROUP_BYs](https://stackoverflow.com/a/45252750/3404097) – philipxy Jan 31 '21 at 00:17
  • I'm guessing at some point you're actually going to attempt to help or will this go on indefinitely? I've spent the last two hours trying to structure my question to the specifications. I can only assume at this point it's hopeless. I have no idea how to give you code that you can copy and paste and run for a MS Access database. – tunneling Jan 31 '21 at 00:18
  • 1
    I just commented on what your problem is. (Maybe your comment crossed my last one.) I would have posted it next on your deleted post but you deleted it too fast. I also gave you comments on how to ask properly which includes doing things that lead to finding errors & not having to post. Also questions that should be closed shouldn't be answered. Also if you pinned down the first bad subexpression & clearly phrased your problem you could google to find one of the many duplicate questions about it. If you don't know how to give a [mre] then research/ask re that 1st. I'm done. – philipxy Jan 31 '21 at 00:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/228065/discussion-between-tunneling-and-philipxy). – tunneling Jan 31 '21 at 01:30

2 Answers2

1

What you need to do is to create summaries of each independently on the project granularity before you join them in a final query.

This change puts all the subqueries to run inside one query. Assuming project_id is a unique key in the project table, this means:

SELECT
    p.[project_id],
    budget_amount,
    actual_amount,
    forecast_amount
FROM
    Project AS p left join 
    (SELECT
    [project_id],
    SUM([amount]) AS budget_amount,
FROM
    Budget
GROUP BY
    [project_id]) AS b on p.project_id=b.project_id
Left join 
    (SELECT
    [project_id],
    SUM([amount]) AS actual_amount,
FROM
    Actuals
GROUP BY
    [project_id]) AS a on p.project_id = a.project_id
Left join 
    (SELECT
    [project_id],
    SUM([amount]) AS forecast_amount,
FROM
    forecast
GROUP BY
    [project_id]) AS f on p.project_id = f.project_id

The project table left joins all other summaries because it is assumed to contain a list of projects which may/may not exist in the other summaries.

Chuma
  • 714
  • 3
  • 7
  • Most of the aliases references are "b". Is that how it should be or is that something I need to work on? – tunneling Jan 31 '21 at 16:53
  • 1
    The alias are just to minimize the use of the long names and only matter within the level in which they are used. Let me see if I can eliminate a bunch of them – Chuma Jan 31 '21 at 17:22
  • i think im going to see i I can migrate the db to mysql. I've tried to do sequential left joins in ms-access before and I can't get it to work. that's why I was doing the ugly join joined with another join. two at a time is all i can get to work. – tunneling Jan 31 '21 at 17:35
  • 1
    The equivalent to msaccess would be SQLite so you don’t need a server and it can just be a file. – Chuma Jan 31 '21 at 17:59
0

I was really hoping for a more elegant approach. Also, I'm fairly confident there's a better way, but this works and hopefully I'll remain employed.

Certainly open to feedback.

SELECT
    project_id,
    budget_amount,
    actual_amount,
    forecast_amount
FROM (
SELECT b.[project_id] as fs_project_id, budget_amount, actual_amount
    FROM
        (   
    SELECT
            b.[project_id],
            SUM(b.[amount]) AS budget_amount
        FROM
            Budget AS b
        GROUP BY
            b.[project_id]
    ) AS q_BudgetSum
        LEFT JOIN (
    SELECT
            a.[project_id],
            SUM(a.[amount]) AS actual_amount
        FROM
            Actuals AS a
        GROUP BY
            a.[project_id]
    ) AS q_ActualSum ON q_ActualSum.[project_id] = q_BudgetSum.[project_id]
) AS FirstSet
    LEFT JOIN
    ( SELECT p.[project_id] as project_id, forecast_amount
    FROM
        (   
    SELECT *
        FROM
            Project AS p
    ) AS q_Project
        LEFT JOIN (
    SELECT
            f.[project_id],
            SUM(f.[amount]) AS forecast_amount
        FROM
            Forecast AS f
        GROUP BY
            f.[project_id]
    ) AS q_ForecastSum ON q_ForecastSum.[project_id] = q_Project.[project_id]
)
AS SecondSet
    ON FirstSet.[fs_project_id] = SecondSet.[project_id];
tunneling
  • 527
  • 6
  • 21
  • 1
    If MSAccess used “with statements” like other sql it would be easier to get to elegant. With sql, my primary goal is usually function first and then maintainability for the person who comes right after me. A year from now, could you glance at the sql and quickly discern intent or is an investigation required every time? So of course simplicity is key. Since it appears you really just want to have all the sql in one place, I would only nest sub-queries once, put parenthesis/brackets around them with an alias and use them in the join. – Chuma Jan 31 '21 at 16:02
  • Can you explain what you mean by "sql in one place"? I tried to put the sub-queries "before" the join with an alias, but couldn't figure out how to get that to work in ms-access. For the production db, I actually have one more table that needs to be aggregated ("Earned Value"), and getting that into the nesting of my solution is making my eyes cross. – tunneling Jan 31 '21 at 16:07
  • 1
    Ok let me modify my answer a bit to demo – Chuma Jan 31 '21 at 16:29
  • 1
    Just made the change and all I did was just embed the individual queries into ( ) as . I also changed them to use left join off of the projects table to ensure that all projects show up in case they are missing in the other summaries. As you can see, it gets messy so ditto on the cross-eying. – Chuma Jan 31 '21 at 16:47