Totaling Records in MS Access - ms-access

I have a query that returns the list of sales by customers, but I would like to know just the customer details and total value of sales. The only way I think of being able to do this is to create a second query based on the first one, remove the fields that cause unique records (e.g. description, goods) so I am only left with customer and sale value and then total/group that.
Is that the only way around or can this be done in one query.

Either this, or you can also copy your existing query, and do the grouping and summing in the copy.
But obviously you need two queries if you want both the full list and the totals query.
Edit: If you only need the totals, then edit the original query. Remove the columns you don't need, group by customer, sum the sale values.

Related

How to get reliable results from first() and last()?

EDIT: See edit below for explanation of why min() and max() are NOT adequate.
=========================
The MS documentation on the functions first() and last() says “Because records are usually returned in no particular order (unless the query includes an ORDER BY clause), the records returned by these functions will be arbitrary.”
Obviously, that makes these functions pretty useless for their intended purpose unless the query includes an ORDER BY. But including that in the query is not a straightforward thing to do because these are "aggregate" functions, so a query that SELECTs on them cannot ORDER BY any other field that is not also submitted to an aggregate function.
I have found that a query based on a single table generally returns results in the order of that table’s primary key. But apparently, that cannot be relied on to always be true and may fail under certain circumstances. There's an excellent discussion of this issue in an article, DFirst/DLast and the Myth of the Sorted Result Set.
That article offers two solutions to this problem:
Option one; you first use the DMin/DMax-Function to retrieve the value from the “sortable” column ... and use this as an additional criterion to your query to retrieve the target record.
Second option; you first create a query just containing the primary key and the max value of the sortable column (e.g. CustomerId and maximum of order date). Then you create a second query on the orders and join the first query in there on these two fields. The results will be all column from the orders table but only for the most recent order of each customer.
Those instructions are pretty complicated, so I'd need to see an example of them implemented in code in order to trust myself to use them myself.
This issue has got to be very common because a lot of businesses need to know the first or last order by a customer that meets some condition. But when I Google "Access query first last "order by"", there are several results that explain the problem, including on StackOverflow, but none that lay out a solution with sample SQL code.
What is the right way to do this, including sample code of doing it?
=========================
Edit:
Many sources online, as well as the comment below by Gustav and the proposed answer by Albert D. Kallal, say you can just use min() and max() instead of first() and last(). Obviously, that's okay if what you want is the value of a field in the record in which that field has the smallest or largest value. That's a trivial problem. What I'm talking about is how to get the value of a field in the record in which some other field has the smallest or largest value.
For example, in the answer by Albert D. Kallal, he wants the first and last tour for each customer, so he can just use min() and max() on the dates of the tours. But what if I want to know the location of the first tour for each customer? Obviously, I can't use min(location). If first() would work in a sensible way and if table [Tours] has the primary key [Date], I should be able to use something like:
(SELECT first(location) from [Tours] where [Customer] = ID_Customer)
I am using code like that and it usually gives me the right answer, but not always. So that is what I need to fix. I understand that I may need to use min() instead of first(). But how do I use min() for this since, as I said, I obviously can't just use min(location)?
Never really grasped what first() and last() does in Access.
As you note, rather common to want say last invoice or whatever.
So, say we have a table of Tours. I want the first tour date, and the last tour date.
Well, this query works:
SELECT MAX(FromDate) as LastTourDate, min(FromDate) as FirstTourDate
FROM tblTours
WHERE FromDate is not null
When I run above, I get this:
So, that gets you the min, and max - and gets you this in one query.
No real need for a order by.
However, often there are more then one table involved.
So, I might in place of JUST the first and last tour date?
I probably want a list of customers, and their first tour they took, and say their last tour. But, then again, that's a different question.
But, you again can order your main table ANY way you want, and still pluck out
(pull the min and max).
So, you can do it this way:
Say, tblMain client (people - customers whatever).
Say, tblMyTours - a list of tours they took (child table).
So, the query can look like this:
SELECT tblMainClient.FirstName, tblMainClient.LastName,
(SELECT Min(FromDate) FROM tblMyTours
WHERE tblMyTours.main_id = tblMainClient.id)
AS FirstTourDate,
(SELECT MAX(FromDate) FROM tblMyTours
WHERE tblMyTours.main_id = tblMainClient.id)
AS LastTourDate
FROM tblMainClient
so, the main query is still tblMainClient - I can order, filter, sort by any column in that main table, but we used two sub-query to get the first tour date and the last tour date. So, it will look say like this:
So, typical, we can use a sub-query, pull the max (or min) value, but restrict the sub query to the one row from our parent/main table.
edit: Get last reocrd, but SOME OTHER column
Ok, so say in our simple example, we want the last tour, but NOT the date, but say some other column - like say the last Tour name.
Ok, so we just modify the sub query to return ONLY the last reocrd, but a different column.
And since dates (say 2 invoices on the same day, or yearly tours might have the SAME name, then we need to ensure that ONLY one reocrd is returned. We do this by using top 1, but ALSO add a order by to be 100%, 200%, 300% sure that ONLY ONE top record is returned.
So, our query to get the last tour name, but based on say most recent tour date?
We can do this:
SELECT FirstName, LastName,
(SELECT TOP 1 TourName FROM tblMyTours
WHERE tblMyTours.main_id = tblMainClient.id
ORDER BY tblMyTours.FromDate DESC, tblMyTours.ID DESC)
AS LastTour
FROM tblMainClient
And that will give us the tour name, but the last one.
This:
So, you ceratinly not limited to using "max()" in that sub query.
However, what happens if we want the Tour Name, Hotel Name, and City of that tour?
In other words, it certainly reasonable that we may well want multiple columns.
There are more ways to do this then flavors of ice cream.
However, I like using the query builder for the first part.
What I do is use the standard query builder, do a join to the table and simple slect all the columns I need.
So, for above tblMainClient, and their tours from tblMyTours?
I build a join - use query builder like this:
So, note how I added the columns TourName, FromDate, HotelName and city from that child table (tblMyTours).
Now, of course the above will return 10 rows for anyone who gone on 10 trips.
So, what we do is add a WHERE clause to the child table, get the LAST pk "id" from tblMyTours, and restrict that child table to the ONE row.
So, the above query builder gives us this:
SELECT tblMainClient.ID, tblMainClient.FirstName, tblMainClient.LastName,
tblMyTours.TourName, tblMyTours.FromDate, tblMyTours.HotelName, tblMyTours.City
FROM tblMainClient
INNER JOIN tblMyTours ON
tblMainClient.ID = tblMyTours.Main_id;
(but, I did not have to write above).
So, we add a where clause to that child table join - get the CHILD table "id" in place of TourName, or Tourdate).
So above becomes this:
SELECT tblMainClient.ID, tblMainClient.FirstName, tblMainClient.LastName,
tblMyTours.TourName, tblMyTours.FromDate, tblMyTours.HotelName,
tblMyTours.City
FROM tblMainClient
INNER JOIN tblMyTours ON tblMainClient.ID = tblMyTours.Main_id
WHERE tblMyTours.ID =
(SELECT TOP 1 ID FROM tblMyTours
WHERE tblMyTours.Main_id = tblMainClient.id
ORDER BY tblMyTours.FromDate DESC, tblMyTours.ID DESC)
Now, above is a bit advanced, but OFTEN we want SEVERAL columns. But, at least the first part of the query, the two tables, and the join was done using the query builder - I did not have to type that part in.
so, if you want JUST one column - differnt then the max() critera, then use top 1 with a order by. Do keep in mind that ONLY ONE RECORD can EVER be retunred by that query - if more then one reocrd is returned, the query enginer will fail and you get a message to this fact.
So, for a produce bought, invoice date? They could by the 1 product 2 times, or 2 invoices on the same day might occur. So, by introduction of the 2nd ORDER BY clause (by ID DESC), then that top 1 will ONLY ever return one row.
So, which of the above two?
Well, if just one column from the child table - easy. But, if you want multiple columns? Then you could probably write up a "messy" solution, but I perfect to just fire up query builder, join in the child table, click on the "several" child values I want. Get the query working - and hey, it all up to this point 100% GUI.
Then we toss in the EXTRA criteria to restrict that child table row to the ONE last row, be it simple last one based on ID DESC, or say TourDate, or whatever.
And now we get this:

Single record of greatest n per group from a table with three identifiers

I have a table in which each record is a single purchase made by a single client.
Purchases can be made in different categories of product and different geographical areas (each of these is a single field).
I can count how many purchases each client has in each combination of product/area like this
Select client_id, product_id, zone_id, COUNT(purchase_id)
Group by client_id, product_id, zone_id
From this I would like to get a table where each record is the client, product and zone with the highest number of purchases. So only one row per client.
How would I go about doing this?
I think I might be able to do it by using NOT EXISTS where there is no record with the same three identifiers and higher COUNT, but as this is part of a much larger query I'm afraid of performance issues.
I also figure I might be able to concatenate the three identifiers into a single one, but I need those identifiers to be in separate fields as I need them for a join in another query this will be part of.
Step 1: Generate a temp table with the 3 columns plus count as you mentioned.
Step 2: Apply a groupwise-max algorithm. Either follow the link you have or check out Groupwise-Max

Create a column with daily number of orders in SSIS?

I'm trying to create a new column with the daily orders (the count of OrderNumber for each day). Since I have data coming from multiple sources, I'm using SSIS. My final table should look like this:
Date | Product Number | Quantity Sold | Number of Orders (for that date)
I've tried using Aggregate, but it's not working because of the other columns. I was thinking about creating a parallel source (the same staging table), on which I would use Aggregate to find the number of daily orders, and then find a way to bring it back to the final table, but there must be an easier way?
Aggregate transform takes and outputs only columns you select. So, for your case, select Date, Product, Quantity and some column for Order Count - we will return to this later. Specify Group by for the first two columns, Sum for the third, and Count for the forth. At output you will receive four columns with desired result.
Source column for Count should represent orders and does not include columns used in the first three functions. If you need to use one of these three columns, create a copy of it with Derived Column transfer. I would not recommend using (*) (all columns) for Count, since it will count rows with Null values as well.

MS Access - Ignore records if I find one that matches

I am using MS Access queries. I have a price list with several items that I am matching to actual invoice data to find discrepancies. Let me get specific. The price list can have duplicate item numbers but the only thing different between them is the frequency (in this example it's mat rentals). Here is a sample of the price list data:
The invoice data that comes in has the items listed by item number but not the frequency. Here is a sample of the invoice data that comes in:
I have a query currently set up to return the difference in the total paid and the total calculated from the price list. The query is just matching on item number and returning the difference [Total Price] - [Price From Price List * Quantity]. Here is how the query returns the data currently:
What I want the query to do is only return a record if there is a problem, meaning the price charged on the invoice is not matching any of the price list prices. If the invoices actually had frequency data, this would not be an issue. However, since the invoices don't, I need to look at the invoice unit price and see if it matches any of the prices on the price list. If it does, I don't have a problem. In the example above, invoice #1 doesn't need to show up because the $1.80 unit price matches the bi-weekly price from the price list and invoice #2 doesn't need to show up because the $1.20 unit price matches the weekly price from the price list. The one problem is invoice #3, because the $2.70 unit price does not match any price for that item on the price list. Now, what price from the price list should I use to calculate the difference? I can use either the minimum or the maximum or the closest one, that part doesn't really matter, I just need to come up with the method and the query to only return the records that don't match any price on the price list.
Let's go with the closest price to calculate the difference. If I use that, then the only record the query should return is:
Hopefully this makes sense. In closing, what I am trying to do is take an invoice record, scan through the price list to find if there is a match on price, and if there isn't, return a record that calculates the difference using the closest amount. If you don't think this can be done with just a design query, then let me know, perhaps I can write a small method.
Thank you in advance for answers!!
You could run a query on Report Price with a left join on Unit Price, keeping all records from the Report. Then filter out any null fields, from Unit Price.
Then your Overpayment, is just an expression, that subtracts one from the other. i.e. "Overpayment: (ReportPrice - UnitPrice) * Units"
You could probably do this with one query, but it wouldn't harm anything, if you wanted to use two.

adding mysql table values

I have a table in my database that holds numerical values collected from a user's input. How could I add those values together and display that number on the website, with the number updating every time a new number is inputed.
SELECT SUM(value) FROM table
Something like this? You should also look into GROUP BY.
EDIT:
It could be you're meaning that you have a value and you want to increment it by n. Then you can look at this example code.
UPDATE table SET value = value + n WHERE id = 123
Where n is the value you want to increment it by.
I would query a master table of IDs that has the running total of values.
Then, via any inserts into some alternate table that keeps each individual entry accounted for, there is a trigger that forces a SQL-Update to the master table... This way, you don't have to keep doing a web-based query that is always doing a GROUP BY for the results.
If this is a little confusing, think of an inventory system. You have one master item table of all possible inventory items. It has an "on hand" count. Then, as sales of an item are sold, the "on hand" count is reduced by however many are purchased. You are not going to each individual sales order and counting grouped by a given ID, you just go to thee master inventory item table and have that "on hand" count.