Ms ACCESS and queries: dates in graph not in order - sql

I use queries in Ms ACCESS to create graphs (shown in forms) to represent monthly spend data on a supplier. I want the x axis to be the months in chronological order, and this is where I'm having issues.
The picture above shows that the x axis starts with april 2016, although the earliest date is august 2015.
The query code that creates the graph is the following:
SELECT (Format([DateStamp],"mmm"" '""yy")) AS Expr1, Sum([Item Master].SpendPerMaterial) AS Expr2
FROM [Item Master]
WHERE ((([Item Master].SupplierName)=[Forms]![Supplier History]![List0]))
GROUP BY (Format([DateStamp],"mmm"" '""yy")), (Year([DateStamp])*12+Month([DateStamp])-1);
[Item Master] is the table were all data is retrieved from. DateStamp refers to the column with months, SpendPerMaterial is the spend of a certain material in that month (which is aggregated since we look at the supplier level, not the material level), and List0 is a list where users can select a supplier from a list of suppliers.

You should never rely on the ordering of results from a query unless you include an explicit order by. In your case, the results are ordered by the columns alphabetically (because of the group by).
You can fix this by adding:
order by max([DateStamp])
to the query.

I would add the following to your query, after your GROUP BY clause:
ORDER BY [datestamp] ASC;

I tried the other suggesions on an aggregate totals by month report and no luck. the only way i could get the actual month labels was by putting labels directly beneath the chart, which means altering it every month!

Related

Running an Access query on a FILTERED table

I have some related tables that I want to run a Totals/Group By query on.
My "Tickets" table has a field called "PickDate" which is the date that the order/ticket was fulfilled.
I want to group by the weekday (name) (a calculated field) so that results for certain customers on the same day of the week are grouped. Then the average ticket completion time can be calculated per customer for each weekday. It would look something like the following.
--CustName---Day---AvTime
Customer 1 - MON - 72.3
- TUE - 84.2
- WED - 110.66
..etc
..etc
..etc
Customer 2 ..
This works fine but the problem I am having is that when this query is run, it works on every record from the tickets table. There are some reasons that, for certain reports, the data that it the query is referencing should be restricted between a date range; for example to track a change in duration over a number of weeks.
In the query properties, there is a property, "filter", to which I can add a string such as:
"([qryCustomerDetails].[PickDate] Between #11/1/2021# And #11/14/2021#)"
to filter the results. The only issue is that since each date is unique, the "group by" of like days such as "Monday" is overridden by this unique date "11/1/2021". The query only works when the PickDate is removed as a field. However, then I can't access it to filter by it.
What I want to achieve would be the same as; in the "Tickets" table itself filtering the results between two dates and then having a query that could run on that filtered table.
Is there any way that I could achieve this?
For reference here is the SQL of the query.
FROM tblCustomers INNER JOIN tblTickets ON tblCustomers.CustomerID = tblTickets.CustomerID
GROUP BY tblCustomers.Customer, WeekdayName(Weekday([PickDate]),False,1), tblCustomers.Round, Weekday([PickDate])
ORDER BY tblCustomers.Round, Weekday([PickDate]);
You probably encountered two issues. The first issue is that to filter results in a totals query by un totaled fields you use HAVING rather than WHERE. the second issue is that calculated fields like Day don't exist at the time of the query. You can't say having Day > Mon. Instead you must repeat the calculation of Day: Having CalculateDay(PickDate) > Monday
The designer will usually figure out whether you want having or where automatically. So here is my example:
this gives you the SQL:
SELECT Tickets.Customer, WeekdayName(Weekday([PickDate])) AS [Day], Avg(Tickets.Time) AS AvTime
FROM Tickets
GROUP BY Tickets.Customer, WeekdayName(Weekday([PickDate])), Tickets.PickDate
HAVING (((Tickets.PickDate) Between #11/16/2021# And #11/17/2021#))
ORDER BY Tickets.PickDate;

SQL Query - Calculating Previous Year Sales

I don't know anything about SQL. I currently have a query that gives me this. Sales for some products by channel/etc (please note this is a very simplified version, there's more fields) by week/period/year:
Basically what I would need is to add a column that gives me the sales for prior year. Basically, transform the table as below. In Excel it would be a simple sumifs that would just sum the same exact criteria aside from the year which would be the previous year.
Is it possible to do this within SQL? The dataset is too large to do it within Excel.
I think you just want lag():
select t.*,
lag(sales) over (partition by channel, product, weekno order by yearno) as prev_sales
from t;
If I understand the data, then periodno is redundant with weekno.

Filter PowerPivot based on multiple Date Criteria

I am trying to apply some Time Intelligence functions in my PowerPivot workbook concerning projects and money received for them. I have three relevant tables; Matters, Payments, and a Date Table.
Each matter has a creationDate, and a closureDate(from a linked table). Likewise, each payment has a date. I have reporting set up decently, but am now trying to use Time intelligence to filter this a bit more clearly.
How can I set a PowerPivot Pivot Table up so that the only Matters which show are those which existed within the period selected. e.g. If I select a slicer for 2014, I don't want to show a matter created in 2015, or one which was closed in 2013. The matter should have been active during the period specified.
Is this possible?
You want to show all the matters EXCEPT those where the CreationDate is after the upper limit of the date range you are looking at or the ClosureDate is before the lower limit of the date range you are looking at.
Assuming you have a data structure like this, where the left-hand table is the Matters and the right-hand one is the Payments:
If you have a calculated field called [Total Payments] that just adds up all the payments in the Payments table, a formula similar to this would work:-
[Payment in Range]:=IF(OR(MIN(Matters[Creation Date])>MAX('Reporting Dates'[Date]),MAX(Matters[Closure Date])<MIN('Reporting Dates'[Date])),BLANK(),[Total Payments])
Here is the result with one month selected in the timeline:
Or with one year selected in the year slicer:
NOTE: in my example, I have used a disconnected date table.
Also, you will see that the Grand Total adds up all the payments because it takes the lowest of all the creation dates and the highest of all the closure dates to determine whether to show a total payment value. If it is important that the Grand Total shows correctly, then an additional measure is required:
[Fixed Totals Payment in Range]:=IF(COUNTROWS(VALUES(Matters[Matter]))=1,[Payment in Range],SUMX(VALUES(Matters[Matter]),[Payment in Range]))
Replace the [Payment in Range] in your pivot table with this new measure and the totals will show correctly, however, this will only work if Matters[Matter] is used as one of the fields in the pivot table.
Use filters & the calculate function.
So, if you're Summing payments, it would look like.....
Payments 2014:= CALCULATE( SUM([Payments]), DateTable[Year]=2014)
The Sum function takes the entirety of payments & the filter function will only capture payments w/in 2014, based on the data connected to your date table.

SQL String Troubles with Multiple Functions

I am using a local Access Database connected to Visual Basic. My query is
SELECT RebateReceived, DatePart('yyyy',[RebateMailedDate]) AS MailedDate, Sum(RebateValue) as MoneyReceived
FROM RebateInfoStorage
where RebateReceived='Received'
group by RebateReceived
having DatePart('yyyy',[RebateMailedDate])
I am trying to get the columns that have the same year and the word(s) that have 'received' to identify the records that need to be summed (Added) together. I am not very familiar with the Group By and Having keywords or the Sum() and DatePart() functions.
So the DBMS will go into the RebateInfoStorage and grab all the rows where RebateReceived = 'Received'. Then, it'll group those records, where each group contains records where the expression DatePart('yyyy', RebateMailedDate) evaluates to the same value (i.e. they have the same year). Then for each group, it'll return a single result row with the year, and the sum of all the RebateValues in that group. Operations happen in that order.
HAVING is like WHERE, but happens after the GROUP BY and is a condition placed on a group of records, whereas WHERE is a condition on a record.
SELECT
YEAR(RebateMailedDate) AS MailedDate,
SUM(RebateValue) as MoneyReceived
FROM
RebateInfoStorage
WHERE
RebateReceived = 'Received'
GROUP BY
YEAR(RebateMailedDate);
EDIT: It would appear that YEAR(x) is a more appropriate function!
You should group by DatePart having RebateReceived='Received'. For more information about the syntax of Having you may refer to http://www.w3schools.com/sql/sql_having.asp
Group by means your output table will be grouped according to unique elements in that column. For example, if there are multiple entry with 2014 as year, they will all be grouped together, and their RebateValue will be added up together. If you are grouping with RebateReceived, all the entry will be added and you will end up with a single sum.

SQL DateDiff Syntax

I have a homework problem that I'm having a lot of trouble with... I don't expect the answer and I truly want to learn it. Could somebody help me out with the syntax?
Problem:
For each Sales Order, show how many days it took to ship the order in order by the longest order, then by Sales Order Number. Display Sales Order Number and the number of days to ship. Include the orders that have not yet shipped.
So far I have:
SELECT SalesOrder.SalesOrderNumber,
DATEDIFF (d, MIN(SalesOrder.OrderDate), MAX(Shipment.ShipmentDate)) AS "DaysToShip"
FROM SalesOrder, Shipment
GROUP BY SalesOrder.SalesOrderNumber;
Sometimes it's helpful to see an intermediate form of your query to evaluate if it's providing the correct data at some stage.
Consider the following query, pulled from your example minus some elements:
SELECT SalesOrder.SalesOrderNumber, SalesOrder.OrderDate, Shipment.ShipmentDate
FROM SalesOrder, Shipment
You should observe the results of this query and see how they differ from what you expect. In this case, you haven't indicated how SalesOrder and Shipment are related. The result will be many more rows than there are orders, with each SalesOrder related to each and every other Shipment record (a cross-join).
Once you provide the correct join condition and achieve the desired results at that stage, try adding in aggregation (GROUP BY, MIN, MAX) and test that form of your query. Finally, when you're convinced that you have the correct inputs, add in DATEDIFF and you'll have your final query.
SELECT SalesOrder.SalesOrderNumber,
DATEDIFF (d, MAX(SalesOrder.OrderDate), MAX(Shipment.ShipmentDate)) AS "DaysToShip"
FROM SalesOrder, Shipment
GROUP BY SalesOrder.SalesOrderNumber;