MS Access "double counting" in a query of queries - ms-access

Apologies if this question is a bit long, but I wanted to explain in detail what it is I am trying to do.
I am developing a database in MS Access 2010/Windows 7 which analyses and reports on incidents (e.g. faults) in an organisation. An incident is reported as beginning at a particular date/time in a particular location for a particular duration. An incident may occasionally cause one or more "live resilience outages" (LRO) which will have the same start-time but can be in different locations and have different durations. So for example a router going out of service in the central technical area for 600 sec might cause live outages of 60 sec and 30 sec in studios 5 and 6 respectively.
I need to report on three date ranges: the month in question, the previous month and the (financial, beginning in April) year to date. So for example the report for March 2012 would consider the periods 01 Mar 2012 - 31 Mar 2012 (month), 01 Feb 2012 - 29 Feb 2012 (previous) and 01 Apr 2011 - 31 Mar 2012 (YTD).
These dates are correctly calculated in a form called ReportCentre. I have three queries to return the LROs for the different date ranges: QueryLROMonth, QueryLROPrevious and QueryLROYTD all of which work properly in isolation (i.e. return the correct values). So for example QueryLROMonth is defined as
SELECT lro.*
FROM lro INNER JOIN incidents ON lro.pid = incidents.id
WHERE (((incidents.begin) Between [Forms]![ReportCentre].[StartMonth] And
[Forms]![ReportCentre].[EndMonth]));
which returns the expected values:
id pid duration facility
6 681 30 23
7 686 857 23
8 735 600 25
9 738 600 25
as does the YTD query
id pid duration facility
1 100 120 25
2 366 5 25
3 380 460 1
4 505 341 23
5 622 0 29
6 681 30 23
7 686 857 23
8 735 600 25
9 738 600 25
20 1297 50 1
So far so good, but now the bit that's got me puzzled. I am trying to design another query which takes the output of the three LRO queries (and some other data), groups it all by facility and calculates things like availability. If I design a totals query and include the Facilities table (for the facility name) and the QueryLROMonth query e.g.
SELECT facilities.facility, Count(QueryLROMonth.id) AS lrocountmonth, Sum(QueryLROMonth.duration) AS lrosecondsmonth
FROM QueryLROMonth INNER JOIN facilities ON QueryLROMonth.facility = facilities.ID
GROUP BY facilities.facility;
This works fine and produces what I expect.
facility lrocountmonth lrosecondsmonth
HQ3 2 887
HQ5 2 1200
but as soon as I introduce the YTD query:
SELECT facilities.facility, Count(QueryLROMonth.id) AS lrocountmonth, Sum(QueryLROMonth.duration) AS lrosecondsmonth, Count(QueryLROYTD.id) AS lrocountytd, Sum(QueryLROYTD.duration) AS lrosecondsytd
FROM QueryLROYTD INNER JOIN (QueryLROMonth INNER JOIN facilities ON QueryLROMonth.facility = facilities.ID) ON QueryLROYTD.facility = facilities.ID
GROUP BY facilities.facility;
for some reason stuff starts being counted reported wrongly. Specifically the two Count columns are multiplied together and so lrocountmonth and lrosecondsmonth are both multiplied by lrocountytd. Similarly lrocountytd and lrosecondsytd are both multiplied by lrocountmonth.
facility lrocountmonth lrosecondsmonth lrocountytd lrosecondsytd
HQ3 6 2661 6 2456
HQ5 8 4800 8 2650
What am I doing wrong? How do I prevent this entanglement?

Your [QueryLROMonth] and [QueryLROYTD] queries each return multiple rows per Facility, but because you are effectively JOINing them on just the Facility_ID you are producing an OUTER JOIN of sorts. For example, if for a given Facility your [Month] query contains 3 rows and your [YTD] query contains 6 rows then your JOIN on Facility_ID alone will produce 18 rows.
You'll want to create aggregation queries that "roll up" the Monthly and YTD numbers by Facility first, so they each have only one row per Facility. You can then use them in your final query to produce the report.
Troubleshooting tip: If your aggregation queries are producing strange results try removing the GROUP BY parts so you can see the underlying rows that are being aggregated.

Related

MySQL Use Distinct or Group By in XREF Table Query

I'm building a php configurator with a series of relationships which I'm controlling with MySQL XREF tables.
There is one XREF table which has multiple dependencies as below:
Table: cto_body_deck_rear_chassis_xref
body_id
deck_type_id
rear_id
chassis_id
22
20
23
13
23
20
18
17
23
20
21
17
23
20
24
17
24
20
18
17
25
21
22
14
Each complete combination is unique although there are similarities between columns; however, I'm getting a duplication problem when selecting from a deck type table, relative to a body id variable passed in the URL.
Table: cto_deck_type
deck_type_id
deck_type_content
20
Single Deck
21
3/4 Length Fixed 2nd Deck
22
Full Length Fixed 2nd Deck
If I use the following MySQL statement:
SELECT d.deck_type_id, d.deck_type_content
FROM cto_deck_type d
LEFT JOIN cto_body_deck_rear_chassis_xref xref
ON xref.deck_type_id = d.deck_type_id
WHERE xref.body_id = 23
I get 3 results, even though each result is identical because the body_id and deck_type_id match 3 times (20).
If the results are identical, I want to group them together or select distinct but I'm not sure what the statement should look like?
Any assistance would be appreciated.
SELECT d.deck_type_id, d.deck_type_content
FROM cto_deck_type d
LEFT JOIN cto_body_deck_rear_chassis_xref xref
ON xref.deck_type_id = d.deck_type_id
WHERE xref.body_id = 23
;; and add the line
GROUP BY d.deck_type_id, d.deck_type_content

SQL Query - Pull data from ambiguous column names for growth/decline %

Re-post due to bad data set and bad formatting. I am trying to divide data from two separate tables that have ambiguous column names.
I am newer to SQL, I know it should be simple, however I just can not figure it out. So far I have tried to rename columns, alias columns, union the table, and select multiple data sets.
I keep hitting roadblocks.
I am trying to measure growth or decline week over week. Ideally I want to take the total sales for Plates and do the following equation: (75/100-1) which would equal a -25% decline from last week.
What would be the best way to go about this?
The two example tables are below
LastWeekData
Product Day Month TotalSales
Plates 7 3 $100
Spoons 7 3 $150
Forks 7 3 $120
CurrentData
Product Day Month TotalSales
Plates 14 3 $75
Spoons 14 3 $100
Forks 14 3 $115
You can use table alias to differentiate the table columns that you want to display. See demo here: http://sqlfiddle.com/#!9/0b0d81/29
select cur.Product,
cur.Day,
cur.Month,
cur.TotalSales as currweek_TotalSales,
pre.TotalSales as lastweek_TotalSales,
round((cur.TotalSales/pre.TotalSales-1)*100) as percent_change
from CurrentData as cur
inner join LastWeekData as pre
on pre.product=cur.product
where datediff(str_to_date(concat_ws('-','0001',cur.month,cur.day),'%Y-%m-%d'),
str_to_date(concat_ws('-','0001',pre.month,pre.day),'%Y-%m-%d'))
= 7
Result:
Product Day Month currweek_TotalSales lastweek_TotalSales percent_change
Plates 14 3 75 100 -25
Spoons 14 3 100 150 -33
Forks 14 3 115 120 -4

Missing values on count in mysql

I'm just stuck with this issue atm and I'm not 100% sure how to deal with it.
I have a table where I'm aggregating data on week
select week(create_date),count(*)
from user
where create_date > '2015-02-01'
and id_customer between 9 and 17
group by week(create_date);
the results that I'm getting have missing values in the count, as shown below
5 334
6 376
7 394
8 405
9 504
10 569
11 709
12 679
13 802
14 936
15 1081
16 559
21 1
24 9
25 22
26 1
32 3
34 1
35 1
For example here from 16 to 21 there a obviously 4 values missing I would like these values to be included and count to be 0. I want this because I want the weeks to be matching with other metrics as we are outputting them in an excel file for internal analysis.
Any help would be greatly appreciated.
The problem is that an sql query cannot really produce data that is not there at all.
You have 3 options:
If you have data for each week in your entire table for the period you are querying, then you can use a self join to get the missing weeks:
select week(t1.create_date), count(t2.id_customer)
from customer t1
left join customer t2 on t1.id_customer=t2.id_customer and t1.create_date=t2.create_date and t2.id_customer between 9 and 17
where t1.create_date > '2015-02-01'
group by week(t1.create_date)
If you have missing weeks from the customer table as whole, then create a helper table that contain week numbers from 1 or 0 (depending on mysql config) to 53 and do a left join to this helper table.
Use a stored procedure that loops through the results of your original query and inserts the missing data in the resultset using a temporary table and then returns the extended dataset as result.
The problem is that there is no data matching your criteria for the missing weeks. A solution will be to join from a table that has all week numbers. For example if you create a table weeknumbers with one field weeknumber containing all the numbers from 0 to 53 you can use something like this
select weeknumber,count(user.*)
from weeknumbers left join user on (weeknumbers.weeknumber=week(user.create_date)
and user.create_date > '2015-02-01'
and user.id_customer between 9 and 17)
group by weeknumber;
Additionaly you might want to limit the week numbers you do not want to see.
The other way is to do it in the application.

Grouping Data in MS Access 2010 based on multiplication

I am a new user to MS Access.
My table has 2 columns: a column for number of days which goes from 0 to 150+ and a column for principal paid (any number say 858576)
There are over 70000 rows.
Row 1 says 70 days and principal paid as 898956
Row 2 says 68 days and principal paid as 13751
Row 3 says 190 days and principal paid as 397159
Row 4 says 11 days and principal paid as 56978
Row 5 says 29 days and principal paid as 9078910
I want a query to return records from 0-30 days, 30-60 days, 60-90 days, 90-120 days, 120-150 days and 150 above and showing sum of principal against each group mentioned above. Can it be done? If so, how?
If you know the maximum number of your days in the table and criteria for dividing into groups, you could try by using the case:
SELECT
SUM(principal_paid),
days_range
FROM
(
SELECT
principal_paid,
CASE days
WHEN BETWEEN 0 AND 30
THEN '0-30'
WHEN BETWEEN 31 AND 60
THEN '31-60'
WHEN BETWEEN 61 AND 90
THEN '61-90'
WHEN BETWEEN 91 AND 120
THEN '91-120'
WHEN BETWEEN 121 AND 150
THEN '121-150'
ELSE 'over 150'
END AS days_range
FROM
yourtable
)
as T
GROUP BY
days_range

SQL queries to get (elo)rating history (for graph, highest points etc)

I'm running a site with user ranking-list based on elo-rating.
I want to provide more statistics to users and I have pretty much covered, but cant really figure out how to make queries for these ones.
Players highest ranking points
Players ranking points history (for graph)
MySQL db has two tables for statistics: ranking_statistics which holds overall statistics:
id, ranking, wins, losses, draws, total6m, total8m, total10m
and ranking_matches which holds statistics for matches played:
id, home_id, away_id, home_ranking, away_ranking, home6m, away6m, home8m, away8m, home10m, away10m, datetime
Here is some sample data from ranking_matches:
46 442 456 30 -30 6 6 5 3 3 4 2013-10-14 21:22:58
54 456 480 34.0391 -34.0391 6 4 6 4 2 1 2013-10-16 17:33:37
55 473 475 30 -30 9 9 7 8 6 4 2013-10-17 03:06:41
and from ranking_statistics:
442 1029.97 7 2 6 120 89 55
456 1003.93 6 2 5 99 84 65
I would want to retrieve players highest ranking points on history (ranking_statistics.ranking holds current points) and that could be retrieved from ranking_matches by quering all matches with players id as home or away and then calculating all ranking changes with highest score remembered (starting points is 1000). With this query, a graph of points history would be drawn also.
I have tried to understand how this is done but could not get it by myself and there doesnt seem to be any similar questions posted (or atleast I did not found any)
Results could be also calculated with PHP because all the data is output with it.
Sample output:
Player id: 442
Current rating: 1029.97
Highest rating: 1054.32 (on 10-23-2013)
For history graph, 2 values need to be retrieved to be able to draw a history line graph, date and rankingpoints.