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)
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 ()
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'
)
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
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.