Calculated Field in subreport - sql

TL:DR I want a whole column of SQL equivalent of excel's COUNTIFS() Function.
I'm still quite new to MS Access, but I'm quite proficient with Excel. I've inherited an Access Database that tracks reasons for delays in a large logistics group, and am trying to build a report showing which reasons come up most.
So, I can output an SQL report showing all the reasons (they're in a table called 'Reasons', so that bit's easy). What I want is a calculated field next to that column, showing how many times each reason has been cited on the [Master Data] Table (field called 'Lateness Reason') in a given date range. And for double extra bonus points, the percentage they come up would be extremely handy.
I've looked online and found COUNTIFS equivalents for a single set of criteria, but in this case I want it calculating on each row of a report. I've also tried a few things myself, but the closest I could figure was:
SELECT Reasons.Reason, Count([Master Data].[ID]) AS Num
FROM Reasons INNER JOIN [Master Data] ON Reasons.[ID] = [Master Data].[Lateness Reason]
WHERE ((([Master Data].[Lateness Reason])=[Reasons].[Reason]));
which has incorrect syntax and possibly a few other problems (that WHERE clause has to apply equally to all lines, doesn't it?). My only other option might be to do a separate calculation for each line and 'union' them together, but that is likely to cause other problems in the future if more reasons get added (and there are quite a lot already).
Firstly, Is it Possible?
Secondly, If so, How??
Many Thanks in advance
EDIT: In response to comments, table structure is as follows;
Table "Reasons" has two columns; "Reason" and "ID"
Table "Master Data" has many columns, the ones I'd be bothered about are "Date", "ID" and "Lateness Reason" (Lateness reason is equivalent to an ID from table 'Reasons')
Table Reasons
ID Reason
___________________
1 | Stock Shortage
2 | Courier Problems
etc | etc
Master Data
ID Date Reason
__________________
1 | 01/01/1980 | 2
2 | 03/05/2020 | 2
etc

This is how I think your query should look like based on the information you provided.
SELECT Reasons.Reason, Count([Master Data].ID) AS Num
FROM Reasons INNER JOIN [Master Data] ON Reasons.ID = [Master Data].[Lateness Reason]
WHERE ((([Master Data].Date) Between [BeginDate] And [EndDate]))
GROUP BY Reasons.Reason;
Replace [BeginDate] and [EndDate] if you're using form control references.
As for the percentages based on the total, you can use text boxes as #June7 has suggested:
Use a total count in the header or footer of the report =Count(*) and then in the detail add a text box with the following control source: =[Num]/Count(*), where Num is the name of the textbox in your report which holds the counted values per reason. In this case, the control source for Num will be Num based on the query given.
Just a side note, naming your field Date is not advised since it's a reserved keyword in MS Access. It can cause unintended issues along the road.

Related

My Joins in query not pulling through correctly

Good evening. Could someone please help me with the following. I am trying to join two tables.The first id wbr_global.gl_ap_details. This stores historic GL information. The second table sandbox.utr_fixed_mapping is where account mapping is stored. For example, ana ccount number 60820 is mapped as Employee relation. The first table needs the mapping from the second table linked on the account number. The output I am getting is not right and way to bug. Any help would be appreciated!
Output
select sandbox.utr_fixed_mapping_na.new_mapping_1,sum(wbr_global.gl_ap_details.amount)
from wbr_global.gl_ap_details
LEFT JOIN sandbox.utr_fixed_mapping_na ON wbr_global.gl_ap_details.account_number = sandbox.utr_fixed_mapping_na.account_number
Where gl_ap_details.cost_center = '1172'
and gl_ap_details.period_name = 'JUL-21'
and gl_ap_details.ledger_name = 'Amazon.com, Inc.'
Group by 1;
I tried adding the cast function but after 5000 seconds of the query running I canceled it.
The query itself appears ok, but minor changes. Learn to use table "aliases". This way you don't have to keep typing long database.table.column all over. Additionally, SQL is easier to read doing it that way anyhow.
Notice the aliases "gl" and "fm" after the tables are declared, then these aliases are used to represent the columns.. Easier to read, would you agree.
Added GL Account number as described below the query.
select
gl.account_number,
fm.new_mapping_1,
sum(gl.amount)
from
wbr_global.gl_ap_details gl
LEFT JOIN sandbox.utr_fixed_mapping_na fm
ON gl.account_number = fm.account_number
Where
gl.cost_center = '1172'
and gl.period_name = 'JUL-21'
and gl.ledger_name = 'Amazon.com, Inc.'
Group by
gl.account_number,
fm.new_mapping_1
Now, as for your query and getting null. This just means that there are records within the gl_ap_details table with an account number that is not found in the utr_fixed_mapping_na table. So, to see WHAT gl account number does NOT exist, I have added it to the query. Its possible there are MULTIPLE records in the gl_ap_details that are not found in the mapping table. So, you may get
GLAccount Description SumOfAmount
glaccount1 null $someAmount
glaccount37 null $someAmount
glaccount49 null $someAmount
glaccount72 Depreciation $someAmount
glaccount87 Real Estate $someAmount
glaccount92 Building $someAmount
glaccount99 Salaries $someAmount
I obviously made-up glaccounts just to show the purpose. You may have multiple where the null's total amount is actually masking how many different gl account numbers were NOT found.
Once you find which are missing, you can check / confirm they SHOULD be in the mapping table.
FEEDBACK.
Since you do realize the missing numbers, lets consider a Cartesian result. If there are multiple entries in the mapping table for the same G/L account number, you will get a Cartesian result thus bloating your numbers. To clarify, lets say your mapping table has
Mapping file.
GL Descr1 NewMapping
1 test Salaries
1 testView Buildings
1 Another Depreciation
And your GL_AP_Details has
GL Amount
1 $100
Your total for the query would result in $300 because the query is trying to join the AP Details GL #1 to EACH of the entries in the mapping file thus bloating the amount. You could also add a COUNT(*) as NumberOfEntries to the query to see how many transactions it THINKS it is processing. Is there some "unique ID" in the GL_AP_Details table? If so, then you could also do a count of DISTINCT ID values. If they are different (distinct is lower than # of entries), I think THAT is your culprit.
select
fm.new_mapping_1,
sum(gl.amount),
count(*) as NumberOfEntries,
count( distinct gl.UniqueIdField ) as DistinctTransactions
from
wbr_global.gl_ap_details gl
LEFT JOIN sandbox.utr_fixed_mapping_na fm
ON gl.account_number = fm.account_number
Where
gl.cost_center = '1172'
and gl.period_name = 'JUL-21'
and gl.ledger_name = 'Amazon.com, Inc.'
Group by
fm.new_mapping_1
Might you also need to limit the mapping table for a specific prophecy or mec view?
If you "think" that the result of an aggregate is wrong, then the easiest way to verify this is to select the individual rows that correlate to 1 record in the aggregate output and inspect the records, looking for duplications.
For instance, pick 'Building Management':
SELECT fixed.new_mapping_1,details.amount,*
FROM wbr_global.gl_ap_details details
LEFT JOIN sandbox.utr_fixed_mapping_na fixed ON details.account_number = fixed.account_number
WHERE details.cost_center = '1172'
AND details.period_name = 'JUL-21'
AND details.ledger_name = 'Amazon.com, Inc.'
AND details.account_number = 'Building Management'
Notice that we tack on a ,* to the end of the projection, this will show you everything that the query has access to, you should look for repeating sections of data that you were not expecting, then depending on which table they originate from your might add additional criteria to the JOIN, or to the WHERE or you might need to group by additional columns.
This type of issue is really hard to comment on in a forum like this because it is highly specific to your schema, and the data contained within it, making solutions highly subjective to criteria you are not likely to publish online.
Generally if you think a calculation is wrong, you need to manually compute it to verify, this above advice helps you to inspect the data your query is using, you should either construct your own query or use other tools to build the data set that helps you to manually compute the correct values, then work them back into or replace your original query.
The speed issues are out of scope here, we can comment on the poor schema design but I suspect you don't have a choice. In the utr_fixed_mapping_na table you should make the account_number have the same column type as the source data, or add a new column that has the data in the original type, then you can setup indexes on the columns to improve the speed of the join.

Report Builder 3.0 - How can I run this report with a large data set?

I am new to developing reports with large amounts of data, so I am looking for some advice with a problem I am having.
I am developing a SSRS report with 6 parameters. Each Parameter has its' own data set that specifies a distinct list of values for the parameters.
The user will be able to choose as many values as they want for each parameter, except for 1 (the date).
The query looks something like;
SELECT [CURR].[PERIOD]
,[CURR].[PERIOD_MTD]
,[CURR].[CATEGORY1]
,[CURR].[CATEGORY2]
,[CURR].[CATEGORY3]
,[CURR].[CATEGORY4]
,[CURR].[CATEGORY5]
,[CURR].[CALCULATION1_ITD]
,[CURR].[CALCULATION2_ITD]
,[CURR].[CALCULATION3_ITD]
,[CURR].[CALCULATION4_ITD]
,[CURR].[CALCULATION1_MTD]
,[CURR].[CALCULATION2_MTD]
,[CURR].[CALCULATION3_MTD]
,[CURR].[CALCULATION4_MTD]
FROM [BIG_TABLE] [CURR] LEFT OUTER JOIN
[BIG_TABLE] [PREV M]
ON [CURR].[PERIOD_MTD] = [PREV M].[PERIOD]
AND [CURR].[CATEGORY1] = [PREV M].[CATEGORY1]
AND [CURR].[CATEGORY2] = [PREV M].[CATEGORY2]
AND [CURR].[CATEGORY3] = [PREV M].[CATEGORY3]
AND [CURR].[CATEGORY4] = [PREV M].[CATEGORY4]
AND [CURR].[CATEGORY5] = [PREV M].[CATEGORY5]
WHERE [CURR].[PERIOD] = #YYYYMM
AND [CURR].[CATEGORY1] IN (#PARAMETER1)
AND [CURR].[CATEGORY2] IN (#PARAMETER2)
AND [CURR].[CATEGORY3] IN (#PARAMETER3)
AND [CURR].[CATEGORY4] IN (#PARAMETER4)
AND [CURR].[CATEGORY5] IN (#PARAMETER5)
This is the problem I am having;
1 parameter has a distinct list of over 5,500 values that the user can choose from. When all of the values are selected, I notice that the parameter field does not populate like the others (Image below).
When the report runs, I get the following error:
This message is pretty ambiguous, but I isolated it to the fact that the report will run with fewer values in this parameter, but not all of them.
I am not sure what else to try. I am thinking this may be a matter of getting a large volume a data through the main data set.
Extra information:
Datasource is accessed with a shared connection to SharePoint
The table that is queried for this report has no indexes. I wonder if this is important because the table has roughly 26.5mill rows.
I would suggest your approach is wrong.
If you are presenting a user with a list of 5000+ items to choose from I'm guessing they would either choose small number of them or want to select all of them, it would be unlikely that they would sit there and choose 100 items from a list.
if this is the case then I would suggest appending an "ALL" option to the list (UNION to your original list) and then amend the query something like this...
WHERE [CURR].[PERIOD] = #YYYYMM
AND (#PARAMETER1 = 'ALL' OR [CURR].[CATEGORY1] IN (#PARAMETER1))
...
...
You might want to also read these previous SO questions and MS Article.
"IN" clause limitation in Sql Server
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/in-transact-sql?view=sql-server-ver15

Merging two different tables to form one but keeping related data

Im a little new to Acess and am trying to understand how to merge tables.
My problem is basically this...
I have 2 reports that can be ran and exported to excel. I want to be able to take both reports, combine them, and import the combined result to a table.
In one report.. call it location detail... has the following fields:
ID (PK, and autonumber)
Day (Date call was done)
CallID (Resets every day to 1, and increases by 1 for every new call)
Lat (Lattitude of call)
Long (Longitude of call)
Cost
In the other report.. call it location summary.. has the following fields:
ID (PK, and autonumber)
Location
City
Lat (Lattitude of call)
Long (Longitude of call)
# of Occurences (Number of times there was a call at that location)
The problem is when you have a call in the same location, even though it was on two seperate days, it automatically groups it into the number of occurances. So I tried to run 2 seperate queries from the same range of dates, one matching lat, other matching long, it shows up with duplicates.. my guess is because the ones that do not have a matching lat (because it already used the field once, even though there were 4 occurences) are showing null value and are added to the query as a duplicate.
I want to add the City Column that matches the long/lat data, to the location details report, and then make that into a new table/ and then be able to run the same reports, and add them to the new table, but somehow ensure there arent any duplicates.
My biggest problem is there isnt any real primary key since the Call ID is Dependent on the Date.... I am not sure how to really accomplish this.
Any help would be much appreciated... I am Stumped.
EDIT:
The first Query is to join lattitudes:
SELECT
[Location Detail Report_142].Day, [Location Detail Report_142].[Call ID],
[Location Detail Report_142].Lat, [Location Detail Report_142].Long
FROM [Location Detail Report_142]
LEFT JOIN [Location Summary Report_14]
ON [Location Detail Report_142].Lat = [Location Summary Report_14].Lat;
The second one matches call id:
SELECT qryRelationshipToLat.Day, qryRelationshipToLat.[Call ID],
[Location Summary Report_14].City
FROM [Location Summary Report_14]
INNER JOIN qryRelationshipToLat
ON [Location Summary Report_14].Long = qryRelationshipToLat.Long
ORDER BY qryRelationshipToLat.Day, [Location Summary Report_14].City;
I was thinking maybe it could be possible to make some sort of if-then statement stating that if call id shows duplicate THEN match Call ID... It has to match both, when the original Location Summary report is uploaded, it has 283 reccords, but it shows duplicate locations grouped into anouther field (#_of_Occurances), so the total amount of calls would be the total amount in the Location Detail report, witch in this case is 288. so when I run the first qry - 305 results, and the second qry turns the 305 to 337. So I end up with a lot of just duplicates I guess, or null value ones.
But the two reports both don't include Call ID or Call Numbers. The only information that they share is the LONG and LAT Coordinates. So I would have to match those first, then assign call ID, date, and city to the corresponding coordinates.
I think that you need to learn how to use a GROUP BY statement to aggregate your table. These links may help:
http://www.sqlteam.com/article/how-to-use-group-by-in-sql-server
http://beginner-sql-tutorial.com/sql-group-by-clause.htm
It's possible also that your table designs have to be revised, and presumably your approach for adding to the call record as well.
I'm sorry to just throw some links at you, but I'm not quite up to analyzing what you have got in order to construct a complete answer, and in any case I think you will have to tackle these areas of learning.

Ms Access : Query to work out percentage

I have a database which currently records the amount of times someone does a certain procedure and they scores they have received. The scoring is done by select a value of either N, B or C.
I currently have written a query which will count the total number of times a procedure is done and the amount of times each score is received.
Here is the result of the query (original: http://www.flickr.com/photos/mattcripps/6673555339/)
and here is the code
TRANSFORM Count(ed.[Entry ID]) AS [CountOfEntry ID]
SELECT ap.AdultProcedureName, ap.Target, Count(ed.[Entry ID]) AS [Total Of Entry ID]
FROM tblAdultProcedures AS ap LEFT JOIN tblEntryData AS ed ON ap.AdultProcedureName = ed.[Adult Procedure]
GROUP BY ap.AdultProcedureName, ap.Target
PIVOT ed.Grade;
If a score of N or B is given that is deemed below standard and C is deemed at standard. Is there a way I can add something to my query which will show me in percentage how many of the procedures we at standard and how many below?
I really cant get my head round this so any help would be great.
Thanks in advance
UPDATE TabProd
SET PrecProd = (PrecProd * 1.1)
WHERE Código IN (1,2,3,4)
I did something very similar to this on a pretty large scale.
My issue was the need to be able to run queries over specific (but user variable) timeframes and output similar percentage of total results in a report.
I won't get into the date issue but my solution was to run the "sum" function on the total line on my specific reject criteria to get totals of the rejects then use a divide expression to create a new column element (defined expression) in the same query pulling from the joined table of "Total net production" - joined by a common reference - job ID.
For your case it sounds like you want to sum the two failure types - which you would simply add defined expressions dividing your total instances into your various failure modes and formatting in your output report as percents. To finish the data portion of your report you then need a third expression defining your "non-fail percent" - which would be 1.0 - N/total - B/total - both of which you will have previously defined in the query to determine the N and B failure rates.
Then its a matter of pulling that information into your report and formatting. It definitely CAN be done.
Hope this helps.

Splitting one table based on criteria and comparing

I'm not quite sure on the best way to phrase this particular query, so I hope the title is adequate, however, I will attempt to describe what it is I need to be able to understand how to do. Just to clarify, this is for oracle sql.
We have a table called assessments. There are different kinds of assessments within this table, however, some assessments should follow others in a logical order and within set time frames. The problems come in when a client has multiple assessments of the same type, as we have to use a fairly inefficient array formula in excel to identify which 'full' assessment corresponds with the 'initial' assessment.
I have an earlier query that was resolved on this site (Returning relevant date from multiple tables including additional table info) which I believe includes a lot of the logic for what is required (particularly in identifying a corresponding event which has occurred within a specified timeframe). However, whilst that query pulls data from 3 seperate tables (assessments, events, responsiblities), I now need to create a query that generates a similar outcome but pulling from 1 main table and a 2nd table to return worker information. I thought the most logical way would be be to create a query that looks at the assessment table with one type of assessment, and then joins to the assessment table again (possibly a temporary table?) with assessment type that would follow the initial one.
For example:
Table 1 (Assessments):
Client ID Assessment Type Start End
P1 1 Initial 01/01/2012 05/01/2012
Table 2 (Assessments temp?):
Client ID Assessment Type Start End
P1 2 Full 12/01/2012
Table 3:
ID Worker Team
1 Bob Team1
2 Lyn Team2
Result:
Client ID Initial Start Initial End Initial Worker Full Start Full End
P1 1 01/01/2012 05/01/2012 Bob 12/01/2012
So table 1 and table 2 draw from the same table, except it's bringing back different assessments. Ideally, there'd be a check to make sure that the 'full' assessment started within X days of the end of the 'initial' assessment (similar to the 'likely' check in the previous query mentioned earlier). If this can be achieved, it's probably worth mentioning that I'd also be interested in expanding this to look at multiple assessment types, as roughly in the cycle a client could be expected to have between 4 or 5 different types of assessment. Any pointers would be appreciated, I've already had a great deal of help from this community which is very valuable.
Edit:
Edited to include solution following MBs advice.
Select
*
From(
Select
I.ASM_SUBJECT_ID as PNo,
I.ASM_ID As IAID,
I.ASM_QSA_ID as IAType,
I.ASM_START_DATE as IAStart,
I.ASM_END_DATE as IAEnd,
nvl(olm_bo.get_ref_desc(I.ASM_OUTCOME,'ASM_OUTCOME'),'') as IAOutcome,
C.ASM_ID as CAID,
C.ASM_QSA_ID as CAType,
C.ASM_START_DATE as CAStart,
C.ASM_END_DATE as CAEnd,
nvl(olm_bo.get_ref_desc(C.ASM_OUTCOME,'ASM_OUTCOME'),'') as CAOutcome,
ROUND(C.ASM_START_DATE -I.ASM_START_DATE,0) as "Likely",
row_number() over(PARTITION BY I.ASM_ID
ORDER BY
abs(I.ASM_START_DATE - C.ASM_START_DATE))as "Row Number"
FROM
O_ASSESSMENTS I
left join O_ASSESSMENTS C
on I.ASM_SUBJECT_ID = C.ASM_SUBJECT_ID
and C.ASM_QSA_ID IN ('AA523','AA1326') and
ROUND(C.ASM_START_DATE - I.ASM_START_DATE,0) >= -2
AND
ROUND(C.ASM_START_DATE - I.ASM_START_DATE,0) <= 25
and C.ASM_OUTCOME <>'ABANDON'
Where I.ASM_QSA_ID IN ('AA501','AA1323')
AND I.ASM_OUTCOME <> 'ABANDON'
AND
I.ASM_END_DATE >= '01-04-2011') WHERE "Row Number" = 1
You can access the same table multiple times in a given query in SQL, simply by using table aliases. So one way of doing this would be:
select i.client,
i.id initial_id,
i.start initial_start,
i.end initial_end,
w.worker initial_worker,
f.id full_id,
f.start full_start,
f.end full_end
from assessments i
join workers w on i.id = w.id
left join assessments f
on i.client = f.client and
f.assessment_type = 'Full' and
f.start between i.end and i.end + X
/* replace X with appropriate number of days */
where i.assessment_type = 'Initial'
Note: column names such as end (that are reserved words in Oracle SQL) should normally be double-quoted, but from the previous question it looks as though these are simplified versions of the actual column names.
From your post, I assume that you're using Oracle here (as I see "Oracle" in the question).
In terms of "temp" tables, Views come right to mind. An Oracle View can give you different looks of a table which is what it sounds like you're looking for with different kinds of assessments.
Don Burleson is a good source for anything Oracle related and he gives some tips on Oracle Views at http://www.dba-oracle.com/concepts/views.htm