How to group within groups in Access - sql

I've been trying for a while and I'm just about to give up. I need to prepare a report that displays Item Numbers, the line they were produced on, and their production date, among other things. So, as you would imagine, each row contains a line number, item number, production date, and information regarding the number of items planned and produced for that entry.
I need to group the rows by line first, that was simple enough, afterwards, I need to group them by week, that also worked like a charm, except the dates were not really in order after this. I would need to apply a sort but by day this time. This works well but it's the next step that causes the most trouble. I also need to group the runs of items produced. For example:
Day - Item
Day 1 - Item A
Day 2 - Item A
Day 3 - Item A
These would be grouped with a footer counting the number of items produced for those consecutive entries. However, sometimes production looks like this:
Day - Item
Day 1 - Item B
Day 2 - Item B
Day 3 - Item A
Day 3 - Item B
I don't see a way to have the items ordered in a particular way that they can be grouped since I'm already ordering/sorting them by date because the date order is messed up by the first group. If I'm to group items at that point I would get one group header/footer per row, meaning it's not working at all.
My client suggests I make it so that when Access "notices the item number changes it gives a total". While that's wonderful in words, it implies that the rows should be sorted by item number and date. He will produce item A for three days, then produce item B for 2 days but part of the problem is that sometimes he will produce A for two and a half days and start B on that third day (following A) so if it's ordered by date, it may put one row above the other since they are on the same day. To my knowledge there is no real way to have Access to just "know" which products are produced first so as to group them after the item number changes. Of course it can keep the order they were entered in but if I ever need them sorted, that order will be lost.
I'm not sure if this is at all possible with this kinda of table structure. If not, can anyone suggest an alternative table structure? Or perhaps there's a way to have the first group by to not mess up the dates, which would allow me to remove the sort by date (although I'm not sure that it would work even if I could do that).
#Steve Kass
Day - Item
Day 1 - Item B
Day 2 - Item B
Day 3 - Item B
Day 3 - Item A
Day 3 - Item C
Day 4 - Item A
Day 5 - Item C
This is how it's laid out in his Excel sheet:
Day - Item
Day 1 - Item B
Day 2 - Item C
Day 3 - Item C
Day 3 - Item A
Day 4 - Item A
Day 4 - Item D
Day 5 - Item D
I've picked letters that represent the alphabetical order of the actual item numbers.
#Abe Miessler, Query so far:
SELECT Planned.Line,
Planned.[Production Date],
Items.[Item Number],
Items.[Bottles/Pallet],
Planned.PQ1,
Planned.AQ1,
Planned.PQ2,
Planned.AQ2,
Planned.PQ3,
Planned.AQ3
FROM Items
INNER JOIN Planned
ON Items.ID = Planned.ItemID;
#David-W-Fenton: Well I'm being asked to have a production summary per run. A run would be described as consecutive production of the same product. Products are produced on one of two lines and there can be multiple entries per day. The report must be grouped first by line so that each group shows entries for that line. That was done with a simple grouping. Within each line grouping I'm required to separate entries by week. Now, within each week, the days are not appearing in order. If the days are not in order we will not see a run simply because a run will most likely happen with consecutive days. One product will be produced for 3 days in a row for example, if these days are mixed up with the other days of the week, there will not be a consecutive, identifiable run. To have the entries in each week be in the correct order (by day) I applied a sort. What I've noticed is that after applying this sort each entry is handled as a separate "group" but without a header/footer. This results in not being able to group by product number afterwards since each entry is within its own "group".

I think you're asking for something impossible. But just in case you aren't, please let us know what order you want if these are your rows:
Day - Item
Day 1 - Item B
Day 2 - Item B
Day 3 - Item A
Day 3 - Item B
Day 3 - Item C
Day 4 - Item A
Day 5 - Item C

You say in a comment that you started with this:
Group by=>line
Group by=>week
Group by=>product number
...but it didn't work "because after grouping by week, they're grouped by week but within the week they're no longer ordered." So you (correctly) added a sorting group, thus:
Group by=>line
Group by=>week
Sort by=>day
Group by=>product number
But you say:
Now it's in order and you can see
consecutive days with the same
products but grouping results in each
row being grouped separately.
Where are the controls displaying the data? In the detail or in the group/sort header? It makes all the difference in the world. To display all records, you use the DETAIL. To show summary data, you use the HEADER. It sounds to me like you're putting your controls in the header instead of the detail.
Can you take a screenshot of your report in design view and insert it into your question? Without it, I don't see how to get any further.

Related

Finding Failures Within Last 3 days of Orders Per Customer

I'm trying to write a query which is confusing me.
In essence, what I'm trying to look for is check the customer, look for the last 3 days where jobs were done and if each day has a failure, then it performs an action on that customer.
So customer A) Could have had jobs all week (I'll use this week as an example), 20/10 (Failure), 19/10 (Failure), 18/10 (Failure) would work
And Customer B) only has jobs fortnightly (20/10) (Failure), 05/10 (Failure), 20/09, (Failure)
What I am confused about, is I am not sure how to filter on the orders where I'm not looking at the orders themselves, but instead 3 seperate days where orders have been done
I was thinking of a top 3 dates, but the customer could have multiple jobs in a day and I need to find all of the orders for the last 3 days where jobs were done
SELECT distinct TOP 3 DATEPART(DAY,od.datetimeCreated), of.uniqueID FROM order.
data od LEFT JOIN order.dataFailure of ON of.orderID = od.orderID
This gives me something similar to what I want, however I still want to see all of the data for those 3 days
Could anyone give me some pointers on how I could go about this?
Sample Data:
Not sure what data would help with this issue, in essence, when the orderID from order.data is inside order.dataFailure, then we consider it a failure, else if it joins as a null, it hasn't failed.
As for dates, I compare the dates on a field called datetimeCreated and datetimeFailed, and then group it by a customer account code
Desired Results:
I need to find the last 3 days where orders were done for that customer, this could be 3 orders a day for the last 3 days, or 1 order a week for the last 3 weeks, and I'm looking to see if there is a failure on each of those days (Being is there a row in the order.datafailure table for each day of the last 3 days)
In this image I have filtered on the customer,
the query needs to be able to look and see that there has been a failure on 2020-03-12, then check the next day, 2019-12-13, also failure and 2015-07-13, no failure

Tableau combining rows with the same info

I have a dashboard in Tableau which shows different payments received - the amount, the date the payment was received, and a calculated field which shows the number days since the payment was received.
However, a lot of payments are the same, with the same amount, and received on the same day; so Tableau collapses these together, and adds the total days since the payments were received together in the final column, i.e. five lots of £5.50, each received on 1st January shows as below (as of 01/02/2018)
Column 1 Column 2 Column 3
£5.50 01/01/2018 155
But I need separate rows for each. Does anyone know how to stop tableau doing this, or of a workaround?
Many thanks.
You could try using RANK_UNIQUE function.
First of all, in the Analysis Menu, uncheck Aggregate Measures.
Then, starting from this data:
You can get this result:
Additionally, you may want to hide Rank from rows just not-showing header.
Is this something close to what you're looking for?
EDIT/UPDATE
In order to get all values and not just for the top rows, just move the Rank at the very beginning of the shelf:

DAX - Need column with row count within past year

I have a table with sales information at the transaction level. We want to institute a new model where we compensate sales reps if a customer has been makes a purchase after more than a year of dormancy. To figure out how much this would have cost historically, I want to add a column with a flag for whether or not each purchase was the Buyer's first in the past 365 days. What I'd like to do is a rowcount in Powerpivot, for all sales made by that customer in the past 365 days, and wrap it in an IF to set the result to 0 or 1.
Example:
Order Date Buyer First Purchase in Year?
1/1/2015 1 1
1/2/2015 2 1
2/1/2015 1 0
4/1/2015 2 0
3/1/2016 2 1
5/1/2017 2 1
Any assistance would be greatly appreciated.
Excellent business use case! It's quite relevant in the business world.
To break this down for you, I will create 3 columns: 2 with some calculations, and 1 with the result. Once you understood how I did this, you can combine all 3 column formulas and make a single column for your dataset, if you like.
Here's a picture of the results:
So here's the 3 columns that I created:
Last Purchase - in order to run this calculation, you need to know when the buyer made their last purchase.
CALCULATE(MAX([Order Date]),FILTER(Table1,[Order Date]<EARLIER([Order Date]) && [Buyer]=EARLIER([Buyer])))
Days Since Last Purchase - now you can compare the Last Purchase date to the current Order Date.
DATEDIFF([Last Purchase],[Order Date],DAY)
First Purchase in 1 Year - finally, the results column. This simply checks to see if it has been more than 365 days since the last purchase OR if the last purchase column is blank (which means it was the first purchase), and creates the flag you want.
IF([Days Since Last Purchase]>365 || ISBLANK([Days Since Last Purchase]),1,0)
Now, you can easily combine the logic of these 3 columns into a single column and get what you want. Hope this helps!
One note I wanted to add is that for this type of analysis it's not a wise move to do row counts as you had originally suggested, as your dataset can easily expand later on (what if you wanted to add more attribute columns?) and then you would have problems. So this solution that I shared with you is much more robust.

Calculating the number of new ID numbers per month in powerpivot

My dataset provides a monthly snapshot of customer accounts. Below is a very simplified version:
Date_ID | Acc_ID
------- | -------
20160430| 1
20160430| 2
20160430| 3
20160531| 1
20160531| 2
20160531| 3
20160531| 4
20160531| 5
20160531| 6
20160531| 7
20160630| 4
20160630| 5
20160630| 6
20160630| 7
20160630| 8
Customers can open or close their accounts, and I want to calculate the number of 'new' customers every month. The number of 'exited' customers will also be helpful if this is possible.
So in the above example, I should get the following result:
Month | New Customers
------- | -------
20160430| 3
20160531| 4
20160630| 1
Basically I want to compare distinct account numbers in the selected and previous month, any that exist in the selected month and not previous are new members, any that were there last month and not in the selected are exited.
I've searched but I can't seem to find any similar problems, and I hardly know where to start myself - I've tried using CALCULATE and FILTER along with DATEADD to filter the data to get two months, and then count the unique values. My PowerPivot skills aren't up to scratch to solve this on my own however!
Getting the new users is relatively straightforward - I'd add a calculated column which counts rows for that user in earlier months and if they don't exist then they are a new user:
=IF(CALCULATE(COUNTROWS(data),
FILTER(data, [Acc_ID] = EARLIER([Acc_ID])
&& [Date_ID] < EARLIER([Date_ID]))) = BLANK(),
"new",
"existing")
Once this is in place you can simply write a measure for new_users:
=CALCULATE(COUNTROWS(data), data[customer_type] = "new")
Getting the cancelled users is a little harder because it means you have to be able to look backwards to the prior month - none of the time intelligence stuff in PowerPivot will work out of the box here as you don't have a true date column.
It's nearly always good practice to have a separate date table in your PowerPivot models and it is a good way to solve this problem - essentially the table should be 1 record per date with a unique key that can be used to create a relationship. Perhaps post back with a few more details.
This is an alternative method to Jacobs which also works. It avoids creating a calculated column, but I actually find the calculated column useful to use as a flag against other measures.
=CALCULATE(
DISTINCTCOUNT('Accounts'[Acc_ID]),
DATESBETWEEN(
'Dates'[Date], 0, LASTDATE('Dates'[Date])
)
) - CALCULATE(
DISTINCTCOUNT('Accounts'[Acc_ID]),
DATESBETWEEN(
'Dates'[Date], 0, FIRSTDATE('Dates'[Date]) - 1
)
)
It basically uses the dates table to make a distinct count of all Acc_ID from the beginning of time until the first day of the period of time selected, and subtracts that from the distinct count of all Acc_ID from the beginning of time until the last day of the period of time selected. This is essentially the number of new distinct Acc_ID, although you can't work out which Acc_ID's these are using this method.
I could then calculate 'exited accounts' by taking the previous months total as 'existing accounts':
=CALCULATE(
DISTINCTCOUNT('Accounts'[Acc_ID]),
DATEADD('Dates'[Date], -1, MONTH)
)
Then adding the 'new accounts', and subtracting the 'total accounts':
=DISTINCTCOUNT('Accounts'[Acc_ID])

Access 2007 Report Group & Sort gives wrong groups and wrong sorts

I am using Access 2007 and I have a table with a column of dates in the standard MM/DD/YYYY format, and a column of as currency. I am working with test data and the records span from 1900 to 2175, with one record for each year, with costs ranging from a few hundred to a few thousand dollars.
I have a report that uses this query as its RecordSource:
SELECT Year(Appliances.DateReplace) AS Years,
Appliances.CostReplace AS Costs
FROM Appliances;
Using the ribbon tool, I have set the Group & Sort to "Group on Years", "from oldest to newest", [custom] "by every 15", "with costs totaled", "with a header section", "with a footer section", and "keep whole group together on one page".
Here is a screenshot of the Group & Sort
and here is a screenshot of the first results
As you can see, the first group contains only 5 records where it should contain 15, and none of the records are in order. The last group (not shown) contains only one record, while the next 18 groups contain the proper 15 results, with the last group containing 1 result.
Adding a secondary Group & Sort that only chooses to Sort by Year will sort the records properly, but it does not fix the number of records shown in the first group.
In the interest of discovering a pattern, I made a list showing the number of records in the first group when I select different intervals for the grouping. The numbers are the interval, followed by the number of records in the first group.
1:1, 6:2, 11:3, 16:4, 21:11,
2:2, 7:4, 12:8, 17:4, 22:14,
3:2, 8:4, 13:11, 18:8, 23:9,
4:4, 9:8, 14:4, 19:18, 24:20,
5:5, 10:10, 15:5, 20:20, 25:25
The intervals that are multiples of 5 all showed the correct results except for 15, and if there's a pattern to the other ones I am not seeing it except for a lot of 4's.
Update:
After playing around with this I have discovered that the interval is causing the starting year to change. For example, choosing an interval of 15 causes the report to start counting from 1890, which gives me only 5 records in the first group because my data starts at 1900. I have not seen discovered any pattern in how the starting year relates to the interval that I choose.