Access Query for Averaging based on Dates - sql

I have a table that looks like this:
╔═════╦═══════════╦══════╦═══════╗
║ ID ║ Attribute ║ Year ║ Month ║
╠═════╬═══════════╬══════╬═══════╣
║ 1 ║ 15.2 ║ 2014 ║ 11 ║
║ 1 ║ 13.1 ║ 2014 ║ 12 ║
║ 1 ║ 5.6 ║ 2015 ║ 1 ║
║ 2 ║ 7.9 ║ 2014 ║ 11 ║
║ 2 ║ 12.3 ║ 2014 ║ 12 ║
║ 2 ║ 45.6 ║ 2015 ║ 1 ║
║ 3 ║ 23.2 ║ 2014 ║ 11 ║
║ 3 ║ 45.7 ║ 2014 ║ 12 ║
║ ... ║ ... ║ ... ║ ... ║
╚═════╩═══════════╩══════╩═══════╝
What I would like to do is average the "Attribute" for each ID over the last year, starting with the current month and year. For example, I might want to find the average of ID = 2 from June,2015 (6/2015) to June, 2014 (6/2014). I am trying to implement this using only a query (no VBA).
I have already been able to average the current year's "Attribute", but that only includes the months passed in this year, not the previous, and the real problem I am having is that the Year and Month are separated into two fields. If they were a date, this would have been trivial.
I have also been able to get the data for the current and previous years with this:
SELECT Table.ID, Table.Year, Table.Month, Table.Attribute
FROM Table
WHERE
(((Table.ID)="Some ID Number")
AND ((Table.Year)=Year(Date())
Or (Table.Year)=Year(Date())-1));
But again, I am stuck with the months and values for each. What is the best course of action? Is there a way to combine the Year and Month field into another query and do something with that (Just throwing out ideas, I'm pretty lost)?

Maybe something like this will work:
Select id, avg(Table.Attribute)
From Table
Where (Year*100 + Month) between 201406 and 201506
Group by id, (Year*100 + Month)

Another approach would be to re-create a strong typed date using DateSerial in a derived table, which you can then use this to do the Group By Id and apply the Average aggregate:
SELECT x.ID, Avg(x.Attribute) AS AvgOfAttribute
FROM (
SELECT MyTable.ID, MyTable.Attribute, DateSerial([Year], [Month],1) AS TheDate
FROM MyTable
) AS x
WHERE (((x.TheDate) >= '2014-06-01' And (x.TheDate) < '2015-06-01'))
GROUP BY x.ID;
Obviously, if you filter by a single ID then there is no need to apply the GROUP BY.

Related

How to Pivot this table on Oracle?

Can you help me figure out how to pivot this table:
╔═══════════╦═════════════╦══════╦════════╦════════╗
║ Big Group ║ Small Group ║ Kids ║ Adults ║ Elders ║
╠═══════════╬═════════════╬══════╬════════╬════════╣
║ 1 ║ 1 ║ 10 ║ 20 ║ 5 ║
║ 1 ║ 2 ║ 15 ║ 10 ║ 10 ║
║ 2 ║ 1 ║ 20 ║ 0 ║ 15 ║
╚═══════════╩═════════════╩══════╩════════╩════════╝
Into something like this?
╔═══════════╦═════════════╦══════╦════════╦════════╦═════════════╦══════╦════════╦════════╗
║ Big Group ║ Small Group ║ Kids ║ Adults ║ Elders ║ Small Group ║ Kids ║ Adults ║ Elders ║
╠═══════════╬═════════════╬══════╬════════╬════════╬═════════════╬══════╬════════╬════════╣
║ 1 ║ 1 ║ 10 ║ 20 ║ 5 ║ 2 ║ 15 ║ 10 ║ 10 ║
║ 2 ║ 1 ║ 20 ║ 0 ║ 15 ║ ║ ║ ║ ║
╚═══════════╩═════════════╩══════╩════════╩════════╩═════════════╩══════╩════════╩════════╝
The number of small groups per Big group is variable, and that's what is being difficult for me to understand how to do it.
Can anyone help me?
Thanks in advance
There is a way but the overhead of using PIVOT is to provide the list of all values which needs to be pivoted.
As you also need each small group to be pivoted we need to create a virtual column between big group and small group to be used in pivot clause as you see below
with table1
as
(select 1 bg
,1 sg,10 kids
,20 adult
from dual
union all
select 1,2,15,25 from dual
union all
select 2,1,20,0 from dual
)
select *
from
(
select t1.*,t1.bg||'_'||t1.sg piv
from table1 t1
)
pivot
(
max(sg) sg,max(kids) kids,max(adult) adult
for piv in ('1_1' as bg1_sg1
,'1_2' as bg2_sg2
,'2_1' as bg2_sg1)
)
order by bg
Demo

Have a SUM(Field_1) not exceed SUM(Field_2)

There might be a better way to accomplish but here is what I have:
Environment - Plex ERP -SQL Query Editor
Back-end - SQL Server 2012
Summary
Parts have a "unit" worth based on manufacturing complexity
Some days we ship part\s. Other days we don't
The part units are summed for each day they are scheduled to ship 'Rel_Units_Calc'
The plant gets credit for 5 units a day (when open) 'Unit_multiplier'
This daily credit is summed for each day 'Unit_Capacity'
In order to prevent an overloading of capacity in a slow month, I need to prevent the plant from getting the 5 unit credit when the SUM(Unit_Capacity) will exceed the SUM(Rel_Units_Calc).
A report will be created that will use a case statement to evaluate if the Rel_Units_Calc > Unit_Capcity, then show red else green.
Detailed Scope
I'm trying to create a sales report that will prevent the sales group from overloading (exceeding the capacity) of the plant. To simplify, lets say we have 3 parts (Part A, B, & C). Part A is simple and worth 1 "Unit". Part B is a little more complex and worth 2 "Units". Part C is the most complex and worth 5 "Units". The plant can process 5 units a day that it is open.
The report will show when a day has been overloaded by showing the color Red and green when days are not overloaded. Any days in red will need to have the sales order moved out.
My approach was to take the units * order quantity to give me the 'Release_Units'. Then I am doing a sum(Release_Units) to show a tally for each day in a field called 'Release_Units_Calc'.
I have another field called 'Unit_Multiplier' that gives the 5 unit per day credit on eligible days (excludes weekends and holidays). Then I am doing a sum(Unit_Multiplier) to show a tally for each day in a field called 'Unit_Capacity'.
The color Red and Green were going to be determined by using a case statement comparing the two columns Release_Units_Calc and Unit_Capacity. When Unit_capacity = Release_Unit then green else red.
This works ok until you look at December when we have a slow down for these parts and then we start banking Unit_Capacity. The Unit_Capacity field continues to accrue the 5 units per day even after it has surpassed the Release_Units_Calc. These parts are not produced in December so think 20 business days * 5 units per day gives us 100 Units on Jan 1 which is not good. Essentially, this would cause the sales group to overwhelm the plant in January as they will have 100 banked units to draw from.
I would like for the Unit_Capacity which again, is a SUM(Unit_Multiplier) to not exceed the Release_Units_Calc which is from SUM(Release_Units).
SQL Below:
This temp table marks the days that should be included for the capacity
SELECT
DISTINCT FDPO.FULL_DATE,
----case statement below to create an include flag. It will exclude weekends unless we have a shipment going out
(CASE WHEN (DATENAME(dw, DATEADD(d,0,FDPO.Full_Date)) NOT IN
('Saturday','Sunday')) THEN 1
WHEN (DATENAME(dw, DATEADD(d,0,FDPO.Full_Date)) IN
('Saturday','Sunday')) AND FDPO.DUE_DATE IS NOT NULL THEN 1
ELSE 0 END) AS 'Include'
INTO #Capacity_Temp1
FROM #FDPO AS FDPO
This temp table uses the include flag to remove the dates that should not accrue capacity and adds a capacity column.
SELECT
CT1.FULL_DATE,
#Unit_Multiplier AS 'Unit_multiplier'
INTO #Capacity_Temp2
FROM #Capacity_Temp1 AS ct1
WHERE ct1.INCLUDE= 1
The temp table below adds the unit multiplier up for each day
SELECT
DISTINCT CT2.FULL_DATE,
CT2.Unit_multiplier,
SUM(CT2.Unit_multiplier) OVER (Order By CT2.FULL_DATE) AS 'Unit_Capacity'
INTO #Unit_Capacity
FROM #Capacity_Temp2 AS CT2
The final display query
SELECT
RUC.FULL_DATE,
RUC.Release_Units,
RUC.Release_Units_Calc,--running talley of the release units
ISNULL(UC.Unit_multiplier,0) AS 'Unit_multiplier',
-- credit units given per day except when closed
UC.Unit_Capacity --running talley of the unit multiplier
FROM #RUC AS RUC
LEFT JOIN #Unit_Capacity AS UC
ON UC.FULL_DATE = RUC.FULL_DATE
The output at present:
╔══════╦═══════════════╦════════════════╦═════════════════╦═══════════════╗
║ DATE ║ Release_Units ║ Rel_Units_Calc ║ Unit_multiplier ║ Unit_Capacity ║
╠══════╬═══════════════╬════════════════╬═════════════════╬═══════════════╣
║ 8/3 ║ 15 ║ 15 ║ 5 ║ 5 ║
║ 8/4 ║ NULL ║ 15 ║ 5 ║ 10 ║
║ 8/5 ║ 20 ║ 50 ║ 5 ║ 15 ║
║ 8/5 ║ 15 ║ 50 ║ 5 ║ 15 ║
║ 8/6 ║ NULL ║ 50 ║ 0 ║ NULL ║
║ 8/7 ║ NULL ║ 50 ║ 5 ║ 20 ║
║ 8/8 ║ NULL ║ 50 ║ 5 ║ 25 ║
║ 8/9 ║ NULL ║ 50 ║ 5 ║ 30 ║
║ 8/10 ║ NULL ║ 50 ║ 5 ║ 35 ║
║ 8/11 ║ NULL ║ 50 ║ 5 ║ 40 ║
║ 8/12 ║ 15 ║ 65 ║ 5 ║ 45 ║
║ 8/13 ║ NULL ║ 65 ║ 0 ║ NULL ║
║ 8/14 ║ NULL ║ 65 ║ 5 ║ 50 ║
║ 8/15 ║ NULL ║ 65 ║ 5 ║ 55 ║
║ 8/16 ║ 10 ║ 75 ║ 5 ║ 60 ║
║ 8/17 ║ NULL ║ 75 ║ 5 ║ 65 ║
║ 8/18 ║ NULL ║ 75 ║ 5 ║ 70 ║
║ 8/19 ║ NULL ║ 75 ║ 0 ║ NULL ║
║ 8/20 ║ NULL ║ 75 ║ 0 ║ NULL ║
║ 8/21 ║ NULL ║ 75 ║ 5 ║ 75 ║
║ 8/22 ║ NULL ║ 75 ║ 5 ║ 80 ║
║ 8/23 ║ NULL ║ 75 ║ 5 ║ 85 ║
║ 8/24 ║ NULL ║ 75 ║ 5 ║ 90 ║
║ 8/25 ║ NULL ║ 75 ║ 5 ║ 95 ║
║ 8/26 ║ 10 ║ 95 ║ 5 ║ 100 ║
║ 8/27 ║ 10 ║ 95 ║ 5 ║ 105 ║
╚══════╩═══════════════╩════════════════╩═════════════════╩═══════════════╝
The problem occurs on 8/22 where we start to exceed the Rel_Units_Calc field. This allows an order to be placed on 8/27 that will not trigger the Red because the Unit_Capacity will be greater than the Rel_Units_Calc.
Sorry for the long post. I'm open to any suggestions if there is a better way to accomplish this.
Thanks in Advance,
Mike

Measure values by measure by date in Rows

I Am trying to receive all the measures by date from a cube, on a row based result.
Something like this:
╔═════════╦══════╦═══════╗
║ Measure ║ Date ║ Value ║
╠═════════╬══════╬═══════╣
║ Meas1 ║ D1 ║ 3 ║
║ Meas1 ║ D2 ║ 8 ║
║ Meas1 ║ D3 ║ 9 ║
║ Meas2 ║ D1 ║ 7 ║
║ Meas2 ║ D2 ║ 4 ║
╚══...════╩═══..═╩═══...═╝
What I have right now is:
WITH
MEMBER [Sales].[Source].[Environment] as "Development"
select
[Sales].[Source].[Environment] ON COLUMNS,
[Measures].AllMembers * [Date].[Date].[Date] ON ROWS
FROM [MyCube]
This returns all the Measures for all the dates in the date dimension.
But how do I add the values here?
Just add any other dimension from your Cube that has an [All] Member.
SELECT
[YourOtherDimension].[YourAttributeWithanALLMEMBER].[All] ON COLUMNS,
NON EMPTY
[Measures].AllMembers *
[Date].[Date].[Date] ON ROWS
FROM [MyCube]

Complex GROUP BY with Django's ORM

I have a Django application that tracks electricity consumption and I'm having a hard time trying to come up with a way to use Django's ORM to fetch some information.
My specific use case is this: I have a set of electricity consumption readings, each with a datetime field, consumption and cost (and a few others but these are the relevant ones). I need to sum the consumption and cost values grouped by month, year, electricity meter and electricity price. In other words, I need to be able to get the total energy consumption value and corresponding cost for each month, of each year, for each price (easier to understand if you look at the table further down the post).
This is my ElectricityReading model and its parent Reading model (separated because we also have consumption readings for water and gas, which also derive from Reading):
from model_utils.models import TimeStampedModel
# Other imports here...
class Reading(TimeStampedModel):
meter = models.ForeignKey(Meter)
datetime = models.DateTimeField() # Terrible property name, I know :)
class Meta:
abstract = True
class ElectricityReading(Reading):
price = models.ForeignKey(ElectricityPrice)
consumption = models.DecimalField(max_digits=18, decimal_places=3,
null=True, blank=True, default=None)
cost = models.DecimalField(max_digits=18, decimal_places=3, null=True,
blank=True, default=None)
Right now I'm doing this with this raw SQL, which I build depending on a few parameters:
SELECT
(EXTRACT(YEAR FROM datetime)) AS reading_date_year,
(EXTRACT(MONTH FROM datetime)) AS reading_date_month,
SUM(consumption) as total_consumption,
SUM(cost) as total_cost,
COUNT(id) as num_readings,
price_id
FROM electricity_reading
WHERE meter_id IN (10)
AND datetime >= '2015-10-01 00:00'
AND datetime <= '2015-12-31 23:59'
GROUP BY reading_date_year, reading_date_month, price_id, meter_id
ORDER BY meter_id, reading_date_year, reading_date_month, price_id
This SQL query results in something like the following data (made up values and simplified column names for better formatting):
╔══════╦═══════╦═════════════╦══════╦══════════════╦═══════╗
║ year ║ month ║ consumption ║ cost ║ num_readings ║ price ║
╠══════╬═══════╬═════════════╬══════╬══════════════╬═══════╣
║ 2015 ║ 10 ║ 600 ║ 804 ║ 456 ║ 1 ║
║ 2015 ║ 10 ║ 728 ║ 471 ║ 1998 ║ 2 ║
║ 2015 ║ 10 ║ 848 ║ 792 ║ 1266 ║ 3 ║
║ 2015 ║ 10 ║ 256 ║ 705 ║ 744 ║ 5 ║
║ 2015 ║ 11 ║ 528 ║ 377 ║ 630 ║ 1 ║
║ 2015 ║ 11 ║ 016 ║ 687 ║ 1680 ║ 2 ║
║ 2015 ║ 11 ║ 240 ║ 826 ║ 1289 ║ 3 ║
║ 2015 ║ 11 ║ 736 ║ 522 ║ 720 ║ 5 ║
║ 2015 ║ 12 ║ 584 ║ 627 ║ 608 ║ 1 ║
║ 2015 ║ 12 ║ 776 ║ 078 ║ 1627 ║ 2 ║
║ 2015 ║ 12 ║ 600 ║ 401 ║ 1410 ║ 3 ║
║ 2015 ║ 12 ║ 864 ║ 842 ║ 744 ║ 5 ║
╚══════╩═══════╩═════════════╩══════╩══════════════╩═══════╝
Using Django's ORM, I think the code I need is something along the lines of the following:
objs = ElectricityReading.objects\
.filter(
meter=10,
datetime__gte='2015-05-01 00:00',
datetime__lte='2015-08-31 23:59'
).only('price_id')\
.annotate(reading_date_year=YearTransform('datetime'))\
.annotate(reading_date_month=MonthTransform('datetime'))\
.annotate(total_consumption=Sum('consumption'))\
.annotate(total_cost=Sum('cost'))\
.annotate(num_readings=Count('id'))\
.order_by('meter_id', 'reading_date_year', 'reading_date_month', 'price_id')
But the SQL it generates is not what I need:
SELECT
id,
price_id,
EXTRACT('year' FROM datetime AT TIME ZONE 'Europe/Lisbon') AS reading_date_year,
EXTRACT('month' FROM datetime AT TIME ZONE 'Europe/Lisbon') AS reading_date_month,
SUM(consumption) AS total_consumption, SUM(cost) AS total_cost,
COUNT(id) AS num_readings
FROM geratriz_electricityreading
WHERE (
datetime >= '2015-05-01 00:00:00+01:00'
AND datetime <= '2015-08-31 23:59:00+01:00'
AND meter_id = 10)
GROUP BY
id,
EXTRACT('year' FROM datetime AT TIME ZONE 'Europe/Lisbon'),
EXTRACT('month' FROM datetime AT TIME ZONE 'Europe/Lisbon')
ORDER BY meter_id ASC, reading_date_year ASC, reading_date_month ASC, price_id ASC
This results in a lot more rows being returned from the database due to not being grouped as I need them to be.
The part of the SQL query I can't seem to replicate with Django's ORM is the GROUP BY clause at the end. Django insists on grouping by ID and I can't seem to find a way to make it group by meter_id and price_id.
Given how much time I spent on this already, I'm inclined to say that what I am trying to accomplish simply isn't possible with Django's ORM but I would love that someone would tell me I am missing something.
Try using values()
objs = ElectricityReading.objects\
.filter(
meter=10,
datetime__gte='2015-05-01 00:00',
datetime__lte='2015-08-31 23:59'
.values('price_id')\
.annotate(reading_date_year=YearTransform('datetime'))\
.annotate(reading_date_month=MonthTransform('datetime'))\
.annotate(total_consumption=Sum('consumption'))\
.annotate(total_cost=Sum('cost'))\
.annotate(num_readings=Count('id'))\
.order_by('meter_id', 'reading_date_year', 'reading_date_month', 'price_id')
This should group the results on price_id. If you were displaying several meters at once instead of meter=10, then you could do values('price_id', 'meter') and it would group on both fields.

Count order of overlapping date ranges in SQL [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm not sure if the title quite paints the correct picture, but I'll attempt to explain. I have a table with start and end dates, and team members IDs (sort of like projects). I need to determine when they overlap, count the number of overlaps, and determine the order of overlap (sorted by the start date). My dummy data should clarify, but it's the latter of the 3 that I really want. Here is my current table:
╔═════════════╦════════════╦════════════╗
║ Team Member ║ Start Date ║ End Date ║
╠═════════════╬════════════╬════════════╣
║ 1 ║ 01/01/2015 ║ 04/01/2015 ║
║ 1 ║ 04/01/2015 ║ 06/01/2015 ║
║ 1 ║ 06/01/2015 ║ 07/01/2015 ║
║ 2 ║ 04/01/2015 ║ 06/01/2015 ║
║ 2 ║ 06/01/2015 ║ 10/01/2015 ║
║ 3 ║ 01/01/2015 ║ 09/01/2015 ║
║ 3 ║ 11/01/2015 ║ 13/01/2015 ║
╚═════════════╩════════════╩════════════╝
And here is what I want:
╔══════════════╦═════════════╦════════════╦════════════╗
║ OverlapOrder ║ Team Member ║ Start Date ║ End Date ║
╠══════════════╬═════════════╬════════════╬════════════╣
║ 0 ║ 1 ║ 01/01/2015 ║ 04/01/2015 ║
║ 1 ║ 1 ║ 04/01/2015 ║ 06/01/2015 ║
║ 0 ║ 1 ║ 06/01/2015 ║ 07/01/2015 ║
║ 0 ║ 2 ║ 04/01/2015 ║ 06/01/2015 ║
║ 1 ║ 2 ║ 06/01/2015 ║ 10/01/2015 ║
║ 0 ║ 3 ║ 01/01/2015 ║ 09/01/2015 ║
║ 0 ║ 3 ║ 11/01/2015 ║ 13/01/2015 ║
╚══════════════╩═════════════╩════════════╩════════════╝
So you can see that team members shouldn't affect each other's overlap order.
I'm using Access SQL at the moment, but shortly moving to SQL Server, so a solution in either is the goal!
P.S. you'll see that the 2nd and 3rd data row have the same start date. The overlap order between these 2 is arbitrary; they can be either way round.
EDIT: Changed sample dataset so it covers a new highlighted possibility. The OverlapOrder column can go from 0 to however high depending on how many projects overlap.
Assuming you are able to migrate to SQL Server 2005 or above, you can try the below solution which uses CTEs to do something like what you want:
;with cte as
(select *, row_number() over (partition by id order by startdate, enddate) rn
from tbl)
select *, case when (datediff(dd,s.startdate,t.enddate) >= 0) then s.rn - 1 else 0 end
from cte s
left join cte t on s.id = t.id and t.rn = s.rn - 1
You should take this with a pinch of salt however, since this solution might well be engineered specifically to the sample data set. I have not tested it out with different cases yet.
Demo