How do I divide the sum of one column by the sum of another column when they are from different tables in Access? - sql

I want to grab the sum of two identically named columns, except they are from two different tables (I have been told to combine them multiple times, unfortunately I do not have a choice in the matter...). I want to then divide these two summed values to find the percentage variation.
Below is the code I wrote, all it does is load infinitely.
SELECT SUM(C.[Market Value]) AS CSUM,
SUM(P.[Market Value]) AS PSUM,
CSUM/PSUM AS Percentage_Variation
FROM JanReport AS P,
FebReport AS C;
I have been unsuccessful in using UNION and JOIN. It seems like this function should be easily doable, as I have been able to sum and find % variation by asset class, I can even get the sum of both columns to show with the Totals function. However I just cannot seem to get them to divide.
Code that worked:
SELECT SUM(FebReport.[Market Value]) AS Curr_Total_MV,
(
SELECT SUM(JanReport.[Market Value]) FROM JanReport
) AS Prior_Total_MV,
SUM(FebReport.[Market Value]) /
(
SELECT SUM([Market Value]) FROM JanReport
) AS Percentage_Variation_In_Total_MV,
IIf(
0.9<Percentage_Variation_In_Total_MV AND
Percentage_Variation_In_Total_MV<1.1,'Pass','Fail') AS Result
FROM FebReport;

Inline SELECT should work here:
SELECT SUM([Market Value]) / (SELECT SUM([Market Value]) FROM JanReport) AS Percentage_Variation,
FROM FebReport;
Update: Two sub-queries each returning just one row can be cross-joined to provide the underlying values:
SELECT
[Current Market Value],
[Previous Market Value],
[Current Market Value] / [Previous Market Value] As Percentage_Variation
FROM
(SELECT SUM([Market Value]) As [Current Market Value] FROM FebReport) AS C,
(SELECT SUM([Market Value]) As [Previous Market Value] FROM JanReport) AS P;

Related

Access/SQL Cumulative Query wth GroupBy

I need a query that basically improves upon a query I already have. My original post was here: Access Cumulative Total by Date
The existing query is a running sum of the energy capacity online as of the end of the year. I need one that makes the same one but broken out by project type, preferably in a crosstab format.
The project capacity and online date is stored in the Projects table and the Alternative Energy Type that I need the table to be grouped by is in a different table, Project Types, and the two are related through a type ID.
I'm not very good with SQL, so I've been trying to just add in the Project Types table from the Access Query Builder, but just adding in another groupby column with the Alternative Energy Type
Original:
SELECT Year(p.[Online Date]) AS yr, (SELECT SUM(p2.[System Size AC])
FROM Projects as p2
WHERE YEAR(p2.[Online Date]) <= YEAR(p.[Online Date])
) AS running_sum
FROM Projects AS p
GROUP BY Year([Online Date]);
Modified (wrong):
SELECT Year(p.[Online Date]) AS yr, (SELECT SUM(p2.[System Size AC])
FROM Projects as p2
WHERE YEAR(p2.[Online Date]) <= YEAR(p.[Online Date])
) AS running_sum, [Project Types].[Alternative Energy Type]
FROM [Project Types] INNER JOIN Projects AS p ON [Project Types].[Type ID] = p.[Project Type]
GROUP BY Year([Online Date]), [Project Types].[Alternative Energy Type];
The results of the modified query just show the total yearly running sum with the Alterntaive Energy Types next to them. This isn't correct because it's just showing the same total over and over, nothing is broken out.
I need it to be broken out so that it answers the question "How much rooftop solar did we have as of 12/31/2015, 12/31/2016, etc and how much offsite wind did we have as of 12/31/2015, 12/31/2016, etc"
You need to add an equality to the correlated subquery by grouping field, Alternative Energy Type:
SELECT t.[Alternative Energy Type],
YEAR(p.[Online Date]) AS yr,
(SELECT SUM(subp.[System Size AC])
FROM Projects subp
INNER JOIN [Project Types] subt
ON subt.[Type ID] = subp.[Project Type]
WHERE YEAR(subp.[Online Date]) <= YEAR(p.[Online Date])
AND subt.[Alternative Energy Type] = t.[Alternative Energy Type]
) AS running_sum
FROM Projects p
INNER JOIN [Project Types] t
ON t.[Type ID] = p.[Project Type]
GROUP BY t.[Alternative Energy Type],
YEAR(p.[Online Date]);
For crosstab, first run a make-table action query since the running sum calculation will cause issues
SELECT *
INTO RunningSumTbl
FROM RunningSumQ
Then run the crosstab:
TRANSFORM Sum(q.running_sum) AS SumOfRunningSum
SELECT r.[Alternative Energy Type]
FROM RunningSumTbl r
GROUP BY r.[Alternative Energy Type]
PIVOT r.[yr];
Use PIVOT clause to subset and order columns:
PIVOT r.[yr] IN (2019, 2018, 2017, 2016, 2015)

mssql: add column with the same value for all rows to search results

I have my query:
SELECT [Shipment Date], [Amount] as [Running Costs], Sum([Amount]) OVER
(ORDER BY [Shipment Date]) as [Total Running Costs]
FROM...
This gets me 3 columns:
Shipment Date | Running Costs | Total Running Costs
I would like to add a fourth column to this query which has the same value for all rows, and the same number of rows as my original query results.
I know you could add for example '999'as Something to the search results, but how can I do the same for a sum of another column (example: Imagine the total sum of the a column in another table is 1500, and I want to have 1500 for all rows in the fourth column. Something like select sum(column_name)?
The database engine is MSSQL.
You can use a nested query
SELECT [Shipment Date], [Amount] as [Running Costs], [Total Running Costs], SUM([Total Running Costs] OVER ())
FROM
(
SELECT [Shipment Date], [Amount] as [Running Costs], Sum([Amount]) OVER
(ORDER BY [Shipment Date]) as [Total Running Costs]
FROM...
)
Nested window function should also work
SUM(SUM([Running costs]) OVER (ORDER BY [Shipment Date])) OVER ()

'Not Like' Not Working

I'm trying to return results for service orders from a table that contains Document No. and Unit of Measure as the column header. The Unit of Measure column contains terms 'EACH', 'CHARGE' and 'HOUR'. I do not want to return any results for any Document No. whose Unit of Measure data contains the term 'Hour' I've tried Unit of Measure Not Like = 'Hour' in my Where clause but I still keep getting results with Hour. See two service orders from table I am trying to query. I dont want to return "Document No. svo-13352.
select [Document No.]
from [Service Line]
where [Unit of Measure] not like 'HOUR'
Something like this should work:
select distinct ([Document No.]) from [Service Line]
where [Document No.] not in
(
select distinct( [Document No.] ) from [Service Line] where [Unit of Measure] like 'HOUR'
)

SQL aggregate and other fields showing in query

I have a query, where I need the MIN of a DateTime field and then I need the value of a corresponding field in the same row.
Now, I have something like this, however I cannot get Price field without putting it also in an aggregate clause, which is not what I want.
SELECT MIN([Registration Time]), Price FROM MyData WHERE [Product Series] = 'XXXXX'
I need the MIN of the Registration Time field and then I just want the corresponding Price field for that row, however how do I show that?
I do also need my WHERE clause as shown.
I'm sure I've overlooked something really obvious. Using SQL Server 2008
If you want just one record with [Registration Time], Price, it'd be as simple as this:
select top 1 [Registration Time], Price
from MyData
where [Product Series] = 'XXXXX'
order by [Registration Time]
If you want minimum [Registration Time] and corresponding Price for all [Product Series], then there's a few approaches, for example, using row_number() function:
with cte as (
select
[Registration Time], Price,
row_number() over(partition by [Product Series] order by [Registration Time]) as rn
from MyData
)
select
[Registration Time], Price, [Product Series]
where rn = 1

sum divided values problem (dealing with rounding error)

I've a product that costs 4€ and i need to divide this money for 3 departments.
On the second column, i need to get the number of rows for this product and divide for the number of departments.
My query:
select
department, totalvalue,
(totalvalue / (select count(*) from departments d2 where d2.department = p.product))
dividedvalue
from products p, departments d
where d.department = p.department
Department Total Value Divided Value
---------- ----------- -------------
A 4 1.3333333
B 4 1.3333333
C 4 1.3333333
But when I sum the values, I get 3,999999. Of course with hundreds of rows i get big differences...
Is there any chance to define 2 decimal numbers and round last value? (my results would be 1.33 1.33 1.34)
I mean, some way to adjust the last row?
In order to handle this, for each row you would have to do the following:
Perform the division
Round the result to the appropriate number of cents
Sum the difference between the rounded amount and the result of the division operation
When the sum of the differences exceeds the lowest decimal place (in this case, 0.01), add that amount to the results of the next division operation (after rounding).
This will distribute fractional amounts evenly across the rows. Unfortunately, there is no easy way to do this in SQL with simple queries; it's probably better to perform this in procedural code.
As for how important it is, when it comes to financial applications and institutions, things like this are very important, even if it's only by a penny, and even if it can only happen every X number of records; typically, the users want to see values tie to the penny (or whatever your unit of currency is) exactly.
Most importantly, you don't want to allow for an exploit like "Superman III" or "Office Space" to occur.
With six decimals of precision, you would need about 5,000 transactions to notice a difference of one cent, if you round the final number to two decimals. Increasing the number of decimals to an acceptable level would eliminate most issues, i.e. using 9 decimals you would need about 5,000,000 transactions to notice a difference of a cent.
Maybe you can make a forth row that will be Total - sum(A,B,C).
But it depends on what you want to do, if you need exact value, you can keep fractions, else, truncate and don't care about the virtual loss
Also can be done simply by adding the rounding difference of a particular value to the next number to be rounded (before rounding). This way the pile remains always the same size.
Here's a TSQL (Microsoft SQL Server) implementation of the algorithm provided by Martin:
-- Set parameters.
DECLARE #departments INTEGER = 3;
DECLARE #totalvalue DECIMAL(19, 7) = 4.0;
WITH
CTE1 AS
(
-- Create the data upon which to perform the calculation.
SELECT
1 AS Department
, #totalvalue AS [Total Value]
, CAST(#totalvalue / #departments AS DECIMAL(19, 7)) AS [Divided Value]
, CAST(ROUND(#totalvalue / #departments, 2) AS DECIMAL(19, 7)) AS [Rounded Value]
UNION ALL
SELECT
CTE1.Department + 1
, CTE1.[Total Value]
, CTE1.[Divided Value]
, CTE1.[Rounded Value]
FROM
CTE1
WHERE
Department < #departments
),
CTE2 AS
(
-- Perform the calculation for each row.
SELECT
Department
, [Total Value]
, [Divided Value]
, [Rounded Value]
, CAST([Divided Value] - [Rounded Value] AS DECIMAL(19, 7)) AS [Rounding Difference]
, [Rounded Value] AS [Calculated Value]
FROM
CTE1
WHERE
Department = 1
UNION ALL
SELECT
CTE1.Department
, CTE1.[Total Value]
, CTE1.[Divided Value]
, CTE1.[Rounded Value]
, CAST(CTE1.[Divided Value] + CTE2.[Rounding Difference] - ROUND(CTE1.[Divided Value] + CTE2.[Rounding Difference], 2) AS DECIMAL(19, 7))
, CAST(ROUND(CTE1.[Divided Value] + CTE2.[Rounding Difference], 2) AS DECIMAL(19, 7))
FROM
CTE2
INNER JOIN CTE1
ON CTE1.Department = CTE2.Department + 1
)
-- Display the results with totals.
SELECT
Department
, [Total Value]
, [Divided Value]
, [Rounded Value]
, [Rounding Difference]
, [Calculated Value]
FROM
CTE2
UNION ALL
SELECT
NULL
, NULL
, SUM([Divided Value])
, SUM([Rounded Value])
, NULL
, SUM([Calculated Value])
FROM
CTE2
;
Output:
You can plug in whatever numbers you want at the top. I'm not sure if there is a mathematical proof for this algorithm.