I am trying to calculate a SUM in an MS Access report the following way:
Group1header - label
Group2header - value
Detail - example
Detail - example
Group2header - value
Detail - example
Group1footer [sum of Group2header value]
Somehow, when more detail rows appear, the sum in group1footer is incorrectly calculated (adds value for each detail).
I can not calculate the sums in the query, because the "value" is already a calculated in the query (a subquery would return to many rows):
(
(
(sl_ticketdetail.weight,0) * sl_ticketdetail.amount
- (
SELECT SUM(sl_invoicedetail.amount)
FROM sl_invoicedetail
WHERE ticketdetailid = sl_ticketdetail.ticketdetailid
)
/ 1000
)
* sl_ticketdetail.cost
)
/ 1000
Any idea on what could be going wrong?
Are you saying your are getting results like this:
Group 1a
Group 2a
Foo1 1
Foo2 1
foo3 2
Group 2a Sum 4
Group 2b
Foo1 3
Foo2 3
Group 2a Sum 6
Group 1a Sum 10
Group 1b
Group 2a
Foo1 4
Foo2 1
foo3 2
Group 2a Sum 7
Group 2b
Foo1 4
Foo2 3
Group 2a Sum 14
Group 1b Sum 21
This is the behaviour I would expect. I was able to do it by putting =Sum([value]) in an unbound field in each group footer (and even in the report footer).
I know 'works for me' isn't very helpful.
Have you labelled the detail's values fields (or the summary fields) with the same name as the data source? Sometime MS Access has weird behaviour if your fields have the same name as their bound data source (I tend to rename them slightly so I'm sure what I'm referring to in code).
Since you already have the Group2 sums pre-calculated in your query they will be repeated for each row of results and therefore cannot be used (as you found out) to calculate the Group 1 totals.
You have two solutions
1) pre-calculate the Group1 totals in your query as well and simply report them liek you do the Group2 totals
2) use code in the Group2 footer format/print events to capture the value and manually increment a running Group1 total
I would say 1) is the easiest - 2) is a little hairy and sometimes results in inaccurate totals if the users pages back and forth
You would have to have the record source of the main report to include the totals for Group 2. Then you would need a sub report with a different record source that is on the detail level.
I think your best bet, is to omit the totals in the query and just let the report do the totals on the details. Later, the user may want totals on the same date but a different grouping (yes, you could create another record source). This should also address if a user applies a filter on the report (You may or may not have given them this option.) on a field other than the grouping.
Related
Have two tables users and user_demographics
users has the basic structure of (does have more fields but not needed here):
id name email gender age ethnicity
1 test1 test1#test.com 1 1 1
2 test2 test2#test.com 1 2 1
3 test3 test3#test.com 2 3 2
4 test4 test4#test.com 3 1 1
5 test5 test5#test.com 2 4 5
**Gender**:
1 - Male,
2 - Female,
3 - Prefer not to say
**Age**:
1 - 16-20,
2 - 21-24,
3 - 25-30,
4 - 31-24
**Ethnicity**:
1 - White,
2 - Black,
5 - Prefer not to say
and so on and currently have around 1000 users.
user_demographics structure is:
coreid, type, option (for the sake of this question 'type' will be text, just to make it clearer)
coreid, type option
1 gender 1
1 gender 2
1 age 1
1 age 3
1 ethnicity 1
2 gender 2
2 gender 3
2 age 3
3 gender 1
On a web based form I have 3 sets of checkbox lists, one for each option gender, age, ethnicity and the a user can select multiple from each. They click update and these details are stored in the mysql database as above. coreid is related to another table, but not relevant here.
What I'm trying to do is get a total count of users for each coreid regardless of what type it is. The count should get smaller the more options you select. So coreid 3 should have the biggest count because I've only selected one option.
Example: coreid 3 is selecting all males
Example: coreid 2 is selecting all (females AND 'prefer not to say') AND age range 25-30
Struggling on how to create a single query that will give me the results I need, hope this makes sense.
The idea behind the over all system is that we have a large form that a user fill outs and we store in the information in the users table. Then a member of the admin team can go in and select these users by selecting options from the various demographics information we have collected. So they might just want to see everyone that has ticked the gender options of 'male' and 'prefer not to say' for example. Another admin member may go in and say they want all males, between the age of 25-30. Or they could just tick all options under gender. The idea is that they can select any combination and get a list of results. At the minute I just need to get a count back for the combination selected.
By the SOUNDS of it, you are probably going to need to do with dynamic SQL where you actually build the query on-the-fly, then execute that. Also, to clarify what I THINK you are asking is as follows. CoreID is like a set of filters that some manager is interested in getting count and or details of specific users. They are interested in
EITHER gender condition (1 or 2)
AND EITHER age condition (1 or 3)
AND just the one ethnicity
to possibly target products that might hit those demographics. So you would pre-query every record for CoreID = 1 then start building your query. You would want to order your query by the TYPE to group common items such as the gender, age, ethnicity categories.
Then, within your either localized code (not indicated such as C#, VB, java, whatever), you would need to build the query in such a way that you parenthesis OR those within same category, and logical AND between different such as
where
( Gender = 1
OR Gender = 2 )
AND ( Age = 1
OR Age = 3 )
AND ( Ethnicity = 1 )
If you are trying to write as a MySQL stored procedure, it would be a type of dynamic SQL query... either way, the WHERE clause needs to be constructed from the Core criteria someone is looking for.
You are correct, the last one would be easiest for CoreID = 3 would be a simple
WHERE ( Gender = 1 )
Clarify language source and I or others might be able to offer additional direction, but if I am accurate, you should try to write your own first pass of code, but I will shoot out a pseudo-code for you something like
Get Records Ordered for one CoreID, order by the type of criteria.
prep variable identifying if pending open Parenthesis
prep variable identifying last "type" building for.
for each record
If new type
if has Open Parenthesis
add closing paren
add logical AND before the next entry we are getting
add open parenthesis
set flag we have open parenthesis
else
since same type as last type, add logical OR
go to next record, repeat.
If after last record we would always need to close parenthesis even if a single criteria
I have a table with records each representing an appointment. I have the name of the contactthe appointment is with, and the date. In another table I have a field that contains how many appointments each contact is supposed to have during the day. There are 12 entries for each contact, because some are expected to have different numbers during different months.
I am able to call up the data for the appropriate contactfor the appropriate month. It looks great in the graph when I count up the number of entries for Contact A and put next to it the expected number of entries from the related table.
The problem I'm running into now is that I need to add up all of the expected appointments between all of the entities. So:
::ContactName:: ::appointments:: ::expected::
Contact A 12 10
Contact B 33 34
Contact C 18 27
Getting the roll up for the actual appointments is easy, a simple COUNT summary field in a subsubsummary section. But what of the expected? Because ContactA had 12 appointments that means that there will be 12 records for them, so putting a summary field for the expected column is would return 120 for all Contact A's. Instead, given the dataset above, I need the calculation to return 71. Does this issue make sense? Any help would be greatly appreciated.
If I am following this correctly, you need to divide the amount of expected appointments between the entries of the group, then total the result. So something like:
Sum ( Entities::Expected ) / GetSummary ( sCount ; EntityID )
(this would be easier if we knew the names of your tables and fields).
P.S. The term "entity" has a specific meaning in the context of a relational database. Consider using another term (e.g. "contacts").
Added:
Using your example data, you should see the following results in the above calculation field:
in the 1st group of 12 records: 10 / 12 = .8333333333333333
in the 2nd group of 33 records: 34 / 33 = 1.0303030303030303
in the 3rd group of 18 records: 27 / 18 = 1.5
When you sum all this up (using a summary field defined as Total of this calculation field), you should get 71 (or a number very near 71, due to rounding errors).
Note: in the above calculation, sCount is a summary field defined in the Appointments table as Count of [ any field that cannot be empty ], and EntityID is the field by which your records are sorted and grouped (and it must be a local field).
I need to create a report which is something similar to a Pivot Table.
The report would be something like below, with more towns
I C S Total
Town1 1 2 3 6
Town2 7 1 1 9
Town3 2 3 1 6
Total 10 6 5 21
In Crystal reports, there is an integrated function called Cross table
(see pictures below)
I'm looking for a similar function in SSRS, if there is any. I parsed the internet but I could not find anything that is relevant
Thanks!
You need a matrix to do so
Select the row, once the matrix created, like the image below and click on the row group and look at the group properties
You then choose the row for which you want to do the grouping like the image below
Repeat the operations for the column group.
You will need to add additional row and columns for the total.
I will do that for the row. You click the row to highlight it and then click on insert rows. You then choose Outside group below like in the picture below
Repeat the operations for the column group.
To have total, please put the following formula in your row and column created outside of the group SUM(COUNT(Fields!name_of_your_field.Value)) and you have the double entry table.
Let me know through the comments if you have any issues, I'll happy to help.
I'm trying to create a report in SSRS where I have a matrix, which has gender as the column headings and specifically defined agegroups as the rows. The report is sorted by date (ie, the records being displayed are filtered by the modifedAt value). My problem is that i wish for all of the age group categories to be displayed, even if the dataset does not return any data for that row.
So, for example, if i set the date to be a date where there are no db rows where there are Age5-16 children in - I still want to display the category name, but just have the cells related to that row to display '0'. Instead, the report just drops the whole row because, obviously the query returns no data.
Is the solution to have a separate dataset that brings back the entire list of categories and then somehow fit them together? I'm stuck here so any help is appreciated!
I can think of a few ways to do this:
DataSet level
Instead of just returning the relevant data in the underlying data in the DataSet, include all the categories you want to display in all cases.
e.g. For a database query it might be the difference between an inner and left join, i.e. going from something like:
select *
from AgeGroup
inner join MyData on ...
to:
select *
from AgeGroup
left join MyData on ...
So the report always has all the age groups to display. Where there are NULL values, just display 0.
I think this is the best option if you have control over the DataSet - you won't have to update your report at all, with luck the actual DataSet changes should be minimal, there is still only one DataSet call, and it's by far the simplest to maintain.
Hard code groups into the report
Here you include a table header row for each group you want to display, so these are always displayed in all cases.
Here you have some sort of conditional expression to display the values, e.g. For each group row it will be tailored to that group:
=Sum(IIf(Fields!AgeGroup.Value = "5-16", Fields!Amount.Value, Nothing)
This is not too flexible and will need updates as you change groups, and doesn't have as many options for layout. There is still only one DataSet call, so that is a plus.
Subreports
You can have a parent DataSet that displays one row for each age group, then embed a subreport in each row that displays the data you want for that row.
This allows you flexibility in layout but it will add complexity to the report(s) and will mean that you make a lot of DataSet calls that could be avoided with other options.
I know this is old, but I wanted to elaborate on Ian's section 1 above using joins at the dataset level. (His answer was super helpful to me for a report I'm working on.)
per op:
Is the solution to have a separate dataset that brings back the entire list of categories and then somehow fit them together?
That is how I've handled it successfully, but you can do so without actually creating a separate dataset by using common table expressions (or temp tables, of course).
For these example tables:
AGE_Table
ID Group Group_Desc Toys
1 A 00-10 Teddy Bear
2 B 11-20 Video Game
3 C 21-30 Sports Car
4 D 31-40 Mansion
5 E 41-50 Jewelry
People_Table (filtered for whatever date)
ID Name Age Gender Age_Group
1 Ariel 07 F A
2 Brandon 23 M C
3 Chelsea 27 F C
4 Derek 06 M A
You want to see 2 results for the 00-10 row, 2 for the 21-30 row, and then still see rows for the other age groups even if there aren't any results.
We want to create a dataset with all the different age groupings and then join on it. Behold a solution using common table expressions:
with CTE_Age AS
(SELECT Distinct Age_Group from AGE_Table)
SELECT ID, Name, Age, Gender, CTE_Age.Age_Group FROM People_Table
RIGHT JOIN CTE_Age ON
People_Table.Age_Group = CTE_Age.Age_Group
This will return:
ID Name Age Gender Age_Group
1 Ariel 7 F A
4 Derek 6 M A
NULL NULL NULL NULL B
2 Brandon 23 M C
3 Chelsea 27 F C
NULL NULL NULL NULL D
NULL NULL NULL NULL E
Once you have that in your dataset, you can change NULL values to 0 on the report builder side -- I think in 2008R2 the default is just blank.
In SSRS 2005 I am reporting on all available posts by regional office, listed by region,office,vacancyID.
I then display a total per office on how many people started in a particular vacancyID by doing a Count(VacancyStartID).
In the same group row with the Count(VacancyStartID) I need to display SUM(VacancyID).
However at present this does not give the correct SUM, because some vacancies have multiple VacancyStartID's and hence the vacancyID is listed few times, like so:
office vacancyID Number_of_vacancies VacancyStartID (person who started a job)
1 1 2 4567
1 1 2 5678
Totals: 4 (needs to be 2) 2
P.S. Note:These questions are not applicable in this instance:
How can I remove duplicate rows?
How do I remove "duplicate" rows from a view?
Using multiple COUNTs and SUMs in a single SQL statement
If it's in the Underlying SQL Server call...
You can do ...SUM(DISTINCT VacancyID)... like you can COUNT (DISTINCT ..)
Edit:
SELECT
col1, col2, SUM(DISTINCT Number_of_vacancies) as foo, COUNT (VacancyStartID) as bar
FROM
MyView
...
If it's in the table or for a cell in the report, then there is no equivalent in the SSRS SUM function.
Do some grouping already in your query and then make a group with a simple Count in SSRS.