Creating Counter that adjusts based on category - ms-access

SELECT Table1.DateBEG, Table1.DateEND, Table2.[HIRE DATE], Table2.Action, Table2.EffectiveDate, IIf([Table2].[HIRE DATE]<=[table1].[action] And [Table2].[Field4]<>"LOA",1,0) AS expr1 FROM Table1, Table2;
I have two Tables as you can see in the images below. One containing ranges, and the other containing an employee id, hire date, effective date, and action.
The idea is to have a counter that counts each range that the hire date fits in, but if there is an instance of an action with "LOA" then the counter stops counting. Only counting the ranges where an effective Date with action LOA isn't present.
My code above doesn't entirely work as it still includes date ranges which include LOA. In the table, the ranges which should count is the second only with the third and first not counting as the first is before the hire date and the thrid range contains an instance of LOA in the date range. If anyone can assist me, it would be much appreciated!

Related

SQL, dropping duplicates but keeping first row to mimic "greatest n per group" functionality

I'm curious about what the best approach for this might be.
Currently, I have a dummy table that stores each time a person clocked in to work. It repeats a lot of info about that employee in each row, e.g. their name, their employee id, position, etc. The main thing different, of course, is the time stamp.
If I want the latest date each employee clocked in, I'm wondering how I would do it via a drop duplicates approach. E.g. in Python, I would sort by date in descending order, and then drop_duplicates on the employee ID column. I'm wondering what the equivalent in SQL is, that isn't the greatest-n-per-group method.
As #Gordon Linoff said if you can share your data table we will be able help you better. But you can try using the MAX Keyword. Like
Select * from your_table t
Where CheckinDate = (select MAX(CheckinDate) from your_table where employeeId = t.employeeId)

Access query to find who didn't test over a range of dates

I am hoping someone can help me out with a query that may not be possible in Access.
I have a table with all employees and a query that shows everyone that has tested over an 18 month or so period and growing.
I am trying to figure out how I can do a query in access that will show what employees have not tested on individual dates within a range of dates. For example, if I create a query of the dates 10/1/17 – 10/14/17 then the result I am hoping for is that Jim did not test on 10/1 and 10/5 and Joe didn't test on 10/12.
It works great for a single date as it compares only the results from a single date query against the employee table and whoever is not in both did not test, but only for that date.
This is the SQL view of the single day “did not test” query:
SELECT ESD_EMP_BADGE.LAST_NAME, ESD_EMP_BADGE.FIRST_NAME, ESD_EMP_BADGE.EMPID, ESD_EMP_BADGE.DEPT
FROM ESD_EMP_BADGE LEFT JOIN Yesterday ON ESD_EMP_BADGE.[EMPID] = Yesterday.[EMPID]
WHERE (((ESD_EMP_BADGE.DEPT) Not Like "EXE") AND ((Yesterday.EMPID) Is Null));
For a range, I cannot do it the same way as the single date query because if that person tested at some time during the range of the query a single test in that range will make it seem like that person tested for all dates.
Is there a way that each date can be considered separately within a single query?
There is only one field that is guaranteed to be unique in the employee table that is also in the test records “EMPID”. There is no date field in the employee table.
I hope this is clear enough of an explanation. I think I might be reaching beyond what Access can do.
If I understand correctly what you are looking for - you will first need a dataset of all possible combinations of employees and test dates. This dataset can be generated with a query that includes employees and tests taken tables without a join clause. This is a Cartesian relationship of records - every record in each table joins with each record in the other table.
SELECT Employees.EmpID, EmpTests.TestDate FROM Employees, EmpTests;
Then join that query back to the testing table.
SELECT Query1.EmpID, Query1.TestDate, EmpTests.TestDate
FROM EmpTests RIGHT JOIN Query1 ON (EmpTests.TestDate = Query1.TestDate) AND (EmpTests.EmpID = Query1.EmpID)
WHERE (((Query1.TestDate) Between [start date] And [end date]) AND ((EmpTests.TestDate) Is Null));

Table Joining (ms Access, sql)

Hoping I’ve not over simplified things,
I have 2 tables: tblTestA and tblTestB
Both tables are linked through their common ID fields.
I’m looking to select all records from tblTestA that have a date greater than #2013/01/01# its Date field.
Then, from this record set, further filter by keeping only those records who have at least 1 non-Null value in Field1 or Field2 from tblTest2 (i.e. remove double Nulls)
Is there a way to modify the following unworkable/pseudo code so that the above is achieved?
SELECT tblTestA.ID, tblTestB.Field1, tblTestB.Field2
FROM tblTestA
WHERE tblTestA.Date > #2013/01/01#
Inner Join tblTestB
On tblTestA.ID= tblTestB.ID
Where (Not IsNull(tblTestB.Field1)) Or (Not IsNull(tblTestB.Field2));
In the real scenario (due to the way the tables are structured, their size, and additional factors) querying only on the non-Null requirement takes very long. Querying only on the date greater than #2013/01/01# requirement takes very little time. So I’m thinking that if we can return the smaller date requirement result set and then use the common ID field to do the second filter on the non-Null check, then, the whole query might complete faster.
Edit:
Modifying the above to...
SELECT tblTestA.ID, tblTestB.Field1, tblTestB.Field2
FROM tblTestA
Inner Join tblTestB
On tblTestA.ID= tblTestB.ID
WHERE tblTestA.Date > #2013/01/01#
AND
(Not tblTestB.Field1 Is Not Null) Or (tblTestB.Field2 Is Not Null);
...returns records that are within the required date range but seems to also link the non-Null filter to that same date range. Entries for Field1 and Field2 may have been entered before the date range requirement filter. I've probably over simplified things from the real scenario, but I'm looking to do 2 things: 1. return records within a date range, and 2. from this result set, filter out any records that do not have at least one non-Null value in Field1 or Field2 from any date range.

Table structure for daily fund data

I want to store daily fund data for approximately 2000 funds over 20 years or more. At first I figured I would just create one giant table with one column per fund and one row per date. I ran into trouble trying to create this table and also realise that a table like that would have a lot of NULL values (almost half the values would be NULL).
Is there a more efficient way of structuring the table or database for quickly finding and fetching the data for a specific fund over hundreds (or thousands) of days?
The alternative way I've thought of doing this is with three columns (date, fund_id, fund_value). This however does not seem optimal to me since both the date and fund_id would be duplicated many times over. Having a few million data points just for the date (instead of a few thousand) seems wasteful.
Which is the better option? Or is there a better way to accomplish this?
Having the three columns you mention is fine. fund_value is the price of fund_id on fund_date. So fund_id and fund_date would be the PK of this table. I don't understand what you mean "having a few million data points just for the date..." If you have 20k funds, a particular date will appear in at most 20k rows -- one for each fund. This is not needless duplication. This is necessary to uniquely identify the value of a particular fund on a particular date. If you added, say, fund_name to the table, that would be needless duplication. We assume the fund name will not change from day to day. Unchanging (static) data about each fund would be contained in a separate table. The field fund_id of this table would then be a FK reference to the static table.
To query the value of the funds on a particular date:
select fund_date as ValueDate, fund_id, fund_value
from fund_value_history
where fund_date = #aDate
and fund_id = #aFund -- to limit to a particular fund
To show the dates a fund increased in value from one day to the next:
select h1.fund_date, h2.fund_value as PreviousValue,
h1.fund_value PresentValue
from fund_value_history h1
join fund_value_history h2
on h2.fund_id = h1.fund_id
and h2.fund_date =(
select max( fund_date )
from fund_value_history
where fund_id = h2.fund_id
and fund_date < h2.fund_date )
where h2.fund_value < h1.fund_value
and fund_id = #aFund;
This would be a sizable result set but you could modify the WHERE clause to show, for example, all funds whose values on a particular date was greater than the previous day, or the values of all funds (or particular fund) on a particular date and the previous day, or any number of interesting results.
You could then join to the static table to add fund name or any other descriptive data.
The three column approach you considered is the correct one. There would be no wasted space due to missing values, and you can add and remove funds at any time.
Have a search for "database normalisation", which is the discipline that covers this sort of design decision.
Edit: I should add that you're free to include other metrics in that table, of course. Since historical data is effectively static you can also store "change since previous day" as well, which is redundant strictly speaking, but may help to optimise certain queries such as "show me all the funds that decreased in value on this day".

SQL Syntax IF/THEN/ELSE

So I've been dreading asking this question - mostly because I'm terrible at logic in excel, and transferring logic statements to SQL is such a struggle for me, but I'm going to try and make this as clear as possible.
I have two tables. One table is historic_events and the other is future_events. Based on future_events, I have another table confidence_interval that calculates a z-score telling me based on how many future_events will occur, how many historic_event data points I will need to calculate a reliable average. Each record in historic_events has a unique key called event_id. Each record in confidence_interval has a field called service_id that is unique. The 'service_id' field also exists in 'historic_events' and they can be joined on that field.
So, with all that being said, based on the count of future events by service_id, my confidence_interval table calculates the z-score. I then need to select records from the historic_events table for each service_id that satisfy the following parameters
Select * EVENT_ID
From historic_events
where END_DATE is within two calendar years from todays date
and count of `EVENT_ID` is >= `confidence_interval.Z_SCORE`
if those parameters are not met, then I want to widen the date value to being within three years.
if those parameters are still not met, I want to widen the date value to being within four years, and then again to five years. If there still aren't enough datapoints after five years, ohwell, we'll settle for what we have. We do not want to look at datapoints that are older than five years.
I want my end result to be a table that has a list of the EVENT_ID and I would re-run the SQL query for each service_id.
I hope this makes sense - I can figure out the SELECT and FROM, but totally getting stuck on the WHERE.