MS-Access show only items that meet multiple criteria - ms-access

I am new to Access and I am looking for a solution that is beyond the ability of the others in my company and may be beyond what access can do.
I have the following fields.
Date: Last Name: First Name: Test1: Test2: Test3:
I am looking for the following to happen.
On any single date a user may test multiple times.
If the user passes all three tests do not show any records with fails or any duplicate passes.
If the user fails any of the three tests, but has multiple failed records only show one.
If the user has the statement "NotUsed" in any field, but a pass in any other keep a single record for that date.
Thank You,

First, you need a primary key column in order to be able to easily and unambiguously identify each record. In Access this is easily achievable with a Autonumber column. Also, in the table designer, click the key symbol for this column. This creates a primary key index. A primary key is a must for every table.
Let us call this column TestID and let's assume that the table is named tblTest.
The problem is that your condition refers to several records; however, SQL expects a WHERE clause that specifies the conditions for each single record. So let’s try to reformulate the conditions:
Keep the record with the most passes for each user.
Keep records with "NotUsed" in any test field.
The first condition can be achieved like this:
SELECT First(TestID)
FROM
(SELECT TestID, [Last Name], [First Name] FROM tblTest
ORDER BY IIf(Test1='pass',1,0) + IIf(Test2='pass',1,0) + IIf(Test3='pass',1,0) DESC)
GROUP BY [Last Name], [First Name]
This gives you the TestID for each user with the most passes. Now, this is not the final result yet, but you can use this query as a subquery in the final query
SELECT * FROM tblTest
WHERE
Test1='NotUsed' OR Test2='NotUsed' OR Test3='NotUsed' OR
TestID IN ( <place the first query here...> )
Is this what you had in mind?
Another thought is about normalization. Your table is not normalized. You are using your table like an Excel sheet. As your database grows you'll get more and more into trouble.
You have two kinds of non-normalization.
One relates to the fact that each user's first name and last name might occur in several records. If, in future, you want to add more columns, like user address and phone number, then you will have to repeat these entries for each user record. It will become increasingly difficult to keep this information synchronized over all the records. The way to go is to have at least two tables: a user table and a test table where the user table has a UserID as primary key and the test table has this UserID as foreign key. Now a user can have many test records but still always has only one unique user record.
The other one (non-normalization) occurs because you have 3 Test fields in a single record. This is less of a problem if your tests always have the same structure and always require 3 tests per date, but even here you have to fall back to the "NotUsed" entries. There are several ways to normalize this, because a database can have different degrees of normalization. The tree ways:
Only one test table with the fields: TestID (PK), UserID (FK), Date, Result, TestNumber.
A test day table with the fields: TestDayID (PK), UserID (FK), Date + a test result table with the fields: TestResultID (PK), TestDayID (FK), Result, TestNumber
Then you can combine the two previous with this addition: Instead of having a TestNumber field, introduce a lookup table containing information on test types with the fields: TestTypeID (PK), TestNo, Description and in the other tables replace the column TestNumber with a column TestTypeID (FK).
See: How to normalize a table using Access - Part 1 of 4 or look at many other articles on this subject.

Related

Insert/Update on table with autoincrement and foreign key

I have a table as such:
id entity_id first_year last_year sessions_attended age
1 2020 1996 2008 3 34.7
2 2024 1993 2005 2 45.1
3 ... ... ...
id is auto-increment primary key, and entity_id is a foreign key that must be unique for the table.
I have a query that calculates first and last year of attendance, and I want to be able to update this table with fresh data each time it is run, only updating the first and last year columns:
This is my insert/update for "first year":
insert into my_table (entity_id, first_year)
( select contact_id, #sd:= year(start_date)
from
( select contact_id, event_id, start_date from participations
join events on participations.event_id = events.id where events.event_type_id = 7
group by contact_id order by event_id ASC) as starter)
ON DUPLICATE KEY UPDATE first_year_85 = #sd;
I have one similar that does "last year", identical except for the target column and the order by.
The queries alone return the desired values, but I am having issues with the insert/update queries. When I run them, I end up with the same values for both fields (the correct first_year value).
Does anything stand out as the cause for this?
Anecdotal Note: This seems to work on MySQL 5.5.54, but when run on my local MariaDB, it just exhibits the above behavior...
Update:
Not my table design to dictate. This is a CRM that allows custom fields to be defined by end-users, I am populating the data via external queries.
The participations table holds all event registrations for all entity_ids, but the start dates are held in a separate events table, hence the join.
The variable is there because the ON DUPLICATE UPDATE will not accept a reference to the column without it.
Age is actually slightly more involved: It is age by the start date of the next active event of a certain type.
Fields are being "hard" updated as the values in this table are being pulled by in-CRM reports and searches, they need to be present, can't be dynamically calculated.
Since you have a 'natural' PK (entity_id), why have the id?
age? Are you going to have to change that column daily, or at least monthly? Not a good design. It would be better to have the constant birth_date in the table, then compute the ages in SELECT.
"calculates first and last year of attendance" -- This implies you have a table that lists all years of attendance (yoa)? If so, MAX(yoa) and MIN(yoa) would probably a better way to compute things.
One rarely needs #variables in queries.
Munch on my comments; come back for more thoughts after you provide a new query, SHOW CREATE TABLE, EXPLAIN, and some sample data.

mysql - It is ok to have n amount of columns?

I know it's possible to have n amount of columns, but is it proper mysql "coding standard"?
Here is what I'm doing:
I am a table student which includes all the students info including testScores:
student
-------
studId
name
age
gender
testId
Instead of putting each individual test answer within the student table, I made a separate table called testAnswers that will hold each students test results:
testAnswers
-----------
testId
ques1
ques2
.
.
.
quesN
Each entry in the testAnswers table corresponds to a specific student in the table student.
Of course, there will be an admin that will be able to add questions and remove questions as each year the test questions may change. So, if the admin were to remove an answer, than that means one of the columns would be removed.
Just to reiterate myself, I know this is possible to edit and remove columns in a table in mysql, but is good "coding standard"?
The answer is a simple and clear: No. That's just not how you should do it except for very few corner cases.
The usual way to approach this is to normalize your database. Normalization follows a standard procedure that (among other things) avoids having a table with columns names ques1, ques2, ques3 ....
This process will lead you to a database with three tables:
students - id, name, and other stuff that applies to one student each
questions - id and question text for each question
answers - this is a N:M relation between students: student_id, question_id, answer_value
Use two tables!
What you are describing is a one to many relationship as there can be one student to many test scores. You would need to have some id as a foreign key to the student_id and put this id in the testAnswers table. You can then set constraints, which tell the database how to handle removal of data.
As one commenter has mentioned, using one table would result in breaking 1nf or first normal form which basically says that you cannot have multiple values for a single column given a particular record - You can't have multiple test scores for the same user in a given table, instead break the data up into two tables.
...of course 2 tables, also could use 3, just remember to insert a studId column also in the testAnswers table (with REFERENCE to the student table) and an INNER JOIN testAnswers ON student.studId=testAnswers.studId at the SELECT query (to read the data).

which one is best way to store multiple values for a single field? Comma separated or Separate Table

I want to store user followers and following member list. Now in order to this, i am thinking to create two columns namely FOLLOWING and FOLLOWER in USER table to store comma separated values of following and followers respectively.
USER TABLE FIELDS:
userid
firstname
lastname
date_of_birth
following //in this we store multiple following_id as comma separated
follower //in this we store multiple follower_id as comma separated
Another way is to create tables namely FOLLOWER and FOLLOWING to store user's followers and following members id in it.
USER TABLE FIELDS:
userid
firstname
lastname
date_of_birth
and
FOLLOWER TABLE FIELDS:
userid
follower_id (also is an user)
and
FOLLOWING TABLE FIELDS:
userid
following_id (also is an user)
Since i am learning database designing, i don't have enough knowledge. So, here i am not getting proper idea of which way is proper? I have searched that using comma separated way is not a good idea but at the same time is it a good way to have multiple tables with NF ? Is there any drawback of using JOINS? Or is there any other effective way to deal with this scenario?
You need just two tables - one to list your users, and one to list who each user is following.
The resulting tables would be like your second proposal, except that the followers table is unnecessary because all of the required data is already in the following table - it's just keyed from the second column instead of the first. That table will need an index on both columns.
The following table whould have one row per relationship per direction. If the users are following each other, you would put two entries in the following table.
CREATE TABLE following (
userid ... NOT NULL,
following_id ... NOT NULL
);
CREATE INDEX idx_user ON following(userid);
CREATE INDEX idx_following on following(following_id);
CREATE UNIQUE INDEX idx_both ON following (userid, following_id); // prevents duplicates
To find the IDs that a particular user is following:
SELECT following_id FROM following WHERE userid = ?
or to find that user's followers:
SELECT userid FROM following WHERE following_id = ?
Use appropriate JOIN clauses if required to expand those queries to return the users' names.
None of the above. One row per follower. Normalize your data and using it will be easy. Make it an abstract mess like you're proposing and you're life will get tougher and tougher as your application grows.

Database design: Foreign keys dilemma

I am building a web based application for a big company and i have a question about the database part. Lets first introduce you to the situation:
There are 4 very tables that are connected with foreign keys:
Table 1: roadlists
roadlist (roadListNumber, vehicleId, driverId, date, start, end, fuel,...)
roadListNumber - primaryKey
vehicleId - foreignKey
driverId - foreignKey
Table 2: drivers
drivers(driverId, firstName, middleName, lastName, and so on...)
driverId - primaryKey
Table 3: vehicles
vehicles(vehicleId, group, type, model, gpsDevice, and so on...)
vehicleId - primaryKey
Table 4: cargo_zones
cargo_zones(zoneId, name, permiter, area, latitures, longtitudes, and so on...)
zoneId - primaryKey
Table 5: roadLists_cargoZones_mapping
roadLists_cargoZones_mapping(roadListNumber, zoneId, spentFuel, tkm, mcm,...)
roadListNumber - foreignKey
So here is the problem:
If i delete a driver from drivers table the value in the roadlists table will be set to NULL or the whole row will be deleted based on the constraints. In the first case if it is set to NULL if somebody lists all the reports for some date he will not be able to see the driver's name who was on duty because its id does not link to any row in the drivers table. In the seconds case if the whole row is removed from the roadlists table the system loses important data.
So how do i deal with this kind of situations?
The preferred way (but not the only way):
Mark a driver as deleted (have a boolean deleted column, or call it IsActive), without actually deleting the driver or related information.
This way you can still historically report. One way to approach this is create views over the table; one view for AllDrivers and one for ActiveDrivers and join to these rather than the table directly, or just add the IsActive predicate to your query WHERE clauses.
The way you deal with this situation is DON'T DELETE the row from the Driver table.
This is information you want to keep. So, don't remove it.
What you might need is a way to mark the Driver row as inactive, archived, unavailable, or whatever. You've got a status change, NOT a delete.
Any queries where you need that driver EXCLUDED, you can add a predicate (a condition in the WHERE clause) to exclude those rows.

Ensure combo of values are unique, but entered any number of times - Mysql

How can I enforce constraint checks to ensure that a given combination of values are unique, but can be entered any number of times?
Example: I have two columns: Group_ID and Group_Name. So all data with Group_ID = 1 will always have Group_Name as 'Test1'. What I want to prevent is someone entering 'Test2' into Group_Name where Group_ID=1. This should fail the insert. All this data is loaded directly into the DB without any UI, hence I cannot enforce these checks in application. So what I need is:
A unique constraint over multiple columns, but only for the given combination without checking how many times they have been entered.
Is there anything built in Mysql to do this?
You should normalize your table a little bit. The group_id,group_name pair should be in a separate table that defines your groups and then the table you're working with should only have group_id. Then you could add a foreign key from your table to the group table to ensure that your group_id values reference real groups.
If you can't normalize your tables then you'll probably have to use a before insert and before update trigger to ensure that Group_ID and Group_Name always come together as required.