Multiple primary & foreign keys Access - ms-access

I am using Access 2007.
Tables:
- Budget Lines (project_id (PK), donor_code (PK), ...)
- Contracts (project_id (FK), donor_code (FK), ...)
PK = Primary Key
FK = Foreign Key
Let's say that I have entered the field project_id in the table Contracts, and I now want to enter the field donor_code: what do I need to do to make sure that I can only choose among the donor_codes that are combined with the project_id that I entered and not all the existing budget codes ?

Well, having 2 fields as primary key has always looked awkward to me.
My suggestion would be to add an autonumber field in your budget_lines table and declare it as the primary key. Then, you can index the 2 other fields to ensure that there are no duplicates.
As far as I understand, you have a Project table and a Donor table which are both linked to the budget lines table. And then you want to link these buddget lines to contracts.
If you input the data directly in the table, I can't seem to find a solution. Still if you input them through a form, with a little of VBA some workarounds can be found.
One way would be to use the after_update event of your combo boxes for ProjectID and Donor_Code to modify the row source of the query of the other combo box of the pair.
The code would look something like that :
Private Sub ProjectID_AfterUpdate()
If Me!ProjectID.Value Is Null Then
Me.DonorCode.RowSource = "SELECT BudgetLines.Donor_Code, BudgetLines.Whatever >FROM BudgetLines;"
Else
Me.DonorCode.RowSource = "SELECT BudgetLines.Donor_Code, BudgetLines.Whatever FROM BudgetLines WHERE BudgetLines.ProjectID= " & [Me]![ProjectID] & ";"
End If
End Sub

Related

Constrains on a child table in mySQL

I have this situation:
MANAGER (ManagerID, Salary, .... , email)
PROJECT (ProjectID, ..., Date)
Since there is relationship M:N between Manager an project, I'll have a third table:
Manager_has_Project( ManagerID, ProjectID )
where ( ManagerID, ProjectID ) is the compound PK for Manager_has_Project
Let's suppose we have to delete a Manager who has created some projects from our database: SQL won't make us do that. We could add the constraint on the fk ManagerID in the child table "ON DELETE CASCADE", but in this case we will lose information about, for example, how many managers worked for a project. The alternative is "ON DELETE SET NULL" but, since ManagerID is part of the compound pK of Manager_has_Project, we can't set a PK as null.
What would recommend to do?
If you want to to keep the information, use soft deletes rather than actually removing the rows.
That is, add a column, say is_deleted or deletion_datetime that indicates that a Manager has been deleted. Then you can keep all the information, even about "deleted" managers.
You can use views so "normal" queries would only return managers who are not deleted.

Is there a way to create a constraint in a table column to prevent duplicate entries?

I am trying to have access constrain duplicate entries in a column.
The reason why is because I have multiple years of salary that can be entered any number of times.
For example,
ID Salary Year
22 $20000 2013
22 $15000 2012
22 $20000 2013 <- Causes duplicate entries in my report
23 $20000 2013 <- Need to have 2013 here though
I want it so that a user cannot enter 2013 more than once in the column of my COMP table.
EDIT: Added ID numbers because I have multiple people in my COMP table. This changes the question.
"I want it so that a user cannot enter 2013 more than once in the column of my COMP table."
Open COMP in Design View.
Select the Year field.
Select the General tab from the "Field Propeties" (down below).
Choose "Yes (No Duplicates)" from the Indexed property dropdown.
Save the changes.
If you prefer to do it with code instead ...
CurrentDb.Execute "ALTER TABLE [COMP]" & vbCrLf & _
"ADD CONSTRAINT uniq_year UNIQUE ([Year])"
Note that statement will not succeed unless the existing [Year] values are unique. Also, both COMP and Year are reserved words. Enclose them in square brackets so the db engine will recognize them as field names and not complain.
If you decide the constraint should be based on 2 fields ...
CurrentDb.Execute "ALTER TABLE [COMP]" & vbCrLf & _
"ADD CONSTRAINT uniq_id_year UNIQUE (ID, [Year])"
You could also create the same unique index/constraint from table Design View, but that is more difficult for me to describe. It may be easier for you to execute the DDL statement, then examine the result in Design View. Just make sure the table is not in Design View when you try to execute the statement.
I created table COMP with Long Integer fields, ID and Year. Then executed this statement as a new query in the query designer:
ALTER TABLE [COMP] ADD CONSTRAINT uniq_id_year UNIQUE (ID, [Year])
Here is a screen capture of my table in Design View after executing that statement.
I don't understand why the same statement is not working for you. So open the table in Design View and find the UI methods to create the unique index as displayed in that picture.
You can Create a unique index on this field
If you create a unique index, Access doesn't allow you to enter a new
value in the field if that value already exists in the same field in
another record. Access automatically creates a unique index for
primary keys, but you might also want to prohibit duplicate values in
other fields. For example, you can create a unique index on a field
that stores serial numbers so that no two products have the same
serial number.
Make your Primary Key based on one (or more) columns. If you need to base it on 2 columns, go into the Design View of the table, highlight the fields you want it based off of, and right click. Choose "Primary Key" from the popup menu. It looks, from a previous comment, you need to prevent duplicates to the combination of ID and Year. So highlight those 2 rows from Design View and make them the Primary Key. This will prevent you from having 2 records in the table with identical information in ID and Year.
Make sure your report is GROUPED by ID and Year, which will prevent duplicates.

Inserting unique records into MS access 2007

So i have been looking around and not finding much. I appologize ahead of time because this is probably the wrong way to do this but it is what it is.
So i have to track class's that co-workers have completed. This is done through a excel sheet that feeds the MS access database. There is 3 fields that are supplied to me.
Full name, Course Name, and Completion Date.
I know that i dont have a primary key here so i am trying to create a query that will only append the unique records pulled from the excel sheet. I can do it based on a single field but need help making my query append it only when both the Full name and Course Name are not the same for example
Joe Somebody, Course#1, 14feb13
Joe Somebody, Course#2, 15feb13
Joe Somebody, Course#1, 15feb13
I need a query that will append the first 2 rows to a table but ignore the third one due to the person already completing course#1. this is what i have so far that basicly turns my name field into a Primary key.
INSERT INTO table [Full name], [Course], [Date]
SELECT excel_table.[Full name], excel_table.[Course], excel_table.[Date]
FROM excel_table
WHERE excel_table.[Full name] Not in (SELECT table.[Full Name] FROM table)
I also have some Is Not Null stuff at the end but i didnt think it would be relevent to the question.
The easiest way to do this so you do not get duplicates is to add an index. In this case, a composite primary key would seem to be the answer. Just select all of the fields you want included in the composite key and click the Primary Key button:
You will not be allowed nulls in any of the fields comprising the primary key, but as long as the combination of the fields is not matched, data in each of the fields can be repeated. So:
Joe Somebody, Course#1, 14feb13 <-- good
Joe Somebody, Course#2, 15feb13 <-- good
Joe Somebody, Course#1, 15feb13 <-- fails
Joe SomebodyElse, Course#1, 14feb13 <-- good
Now, if you run an ordinary append query build with the query design window, you will get an error if the record exists twice in the Excel import table or already exists in Access:
You don't actually need a composite primary key. In fact there are a few places in Access where you are encouraged to not use a composite primary key. You can create your Access table with a simple integer primary key:
create table CourseCompletions (
ID autoincrement primary key
, FullName varchar(100)
, CourseName varchar(100)
, CompletionDate date
);
Then you can gulp in all the data from the Excel file:
insert into CourseCompletions (
, FullName
, CourseName
, CompletionDate
) select
[Full name]
, [Course]
, [Date]
from excel_table;
This will give each row of your input Excel table a unique number and stash it in the Access table. Now you need to decide how you want to reject conflicting rows from your CourseCompletions table. (The following queries show only the records that you decide to not reject.) If you want to reject completions by the same person of the same course at a later date:
select
ID
, FullName
, CourseName
, min(CompletionDate)
from CourseCompletions
group by
ID
, FullName
, CourseName;
If you want to reject completions at an earlier date simply change the MIN to MAX.
If you want to reject any course completion that appeared earlier in the Excel table:
select
cc1.ID
, cc1.FullName
, cc1.CourseName
, cc1.CompletionDate
from CourseCompletions as cc1
inner join (
select
max(ID) as WantedID
, FullName
, CourseName
from CourseCompletions
group by FullName, CourseName
) as cc2
on cc1.ID = cc2.WantedID;
And to reject course completions that appeared later in the Excel table, simply replace MAX with MIN.
So using an integer primary key gives you some options.

How to add a checkbox in a form next to a query to append to another table

I am building a training database.The tables I am using are: Employees, Training Courses, In Training, and Completed Training. I have a query that filters off of a form to show employees that have not received the training.
I want to add a checkbox next to the results so I can select some or all of them to be added to the In Training table. I have been stuck on this for days searching the internet and reading books looking for the answer.
Just saw this question. Here is an alternative solution to this problem. There is no checkbox, but you get a subform with combo box to update the course and progress for a particular employee.
Create 4 tables with the fields:
tblEmployees
EmployeeID (Primary Key)
EmployeeName (and any additional fields you might need)
tblProgress -> this stores "IN TRAINING", "COMPLETED" as 2 separate records
ID (AutoNumber) (Primary Key)
ProgressDesc
tblTrainingCourses
CourseID (Primary Key)
CourseName
tblEmployeeTraining -> here we are using composite key
EmployeeID (Primary Key)
CourseID (Primary Key)
Progress
Create a one-to-many relationship between tblEmployees and tblEmployeeTraining, linking the EmployeeID.
Configure the following fields in tblEmployeeTraining (in Design View), by selecting the [Lookup Wizard...] from Data Type column.
CourseID
Choose the tblTrainingCourses as the table for the Lookup Values
Progress
Choose the tblProgressas as the table for the Lookup Values
Create a Form based on the tblEmployees. You should get a subform included that will display the Course Name and Progress. Basically, the 2 columns in the subform will show combo box for you to select the course and the progress.
If you do not want the relationship in step 2, maybe you want to store the employee data after it is deleted, then you need to create a query and use it as the RecordSource for the subform. Instead of deleting the record from tblEmployees, you may want to add a field in tblEmployees to determine if the employee is active or not. Then, you can use the above steps and just do filtering on the form to display those active employees.

How to make proper use of foreign keys

I'm developing a helpdesk-like system, and I want to employ foreign keys, to make sure the DB structure is decent, but I don't know if I should use them at all, and how to employ them properly.
Are there any good tutorials on how (and when) to use Foreign keys ?
edit The part where I'm the most confused at is the ON DELETE .. ON UPDATE .. part, let's say I have the following tables
table 'users'
id int PK auto_increment
department_id int FK (departments.department_id) NULL
name varchar
table 'departments'
id int PK auto_increment
name
users.department_id is a foreign key from departments.department_id, how does the ON UPDATE and ON DELETE functions work here when i want to delete the department or the user?
ON DELETE and ON UPDATE refer to how changes you make in the key table propagate to the dependent table. UPDATE means that the key values get changed in the dependent table to maintain the relation, and DELETE means that dependent records get deleted to maintain the integrity.
Example: Say you have
Users: Name = Bob, Department = 1
Users: Name = Jim, Department = 1
Users: Name = Roy, Department = 2
and
Departments: id = 1, Name = Sales
Departments: id = 2, Name = Bales
Now if you change the deparments table to modify the first record to read id = 5, Name = Sales, then with "UPDATE" you would also change the first two records to read Department = 5 -- and without "UPDATE" you wouldn't be allowed to make the change!
Similarly, if you deleted Department 2, then with "DELETE" you would also delete the record for Roy! And without "DELETE" you wouldn't be allowed to remove the department without first removing Roy.
You will need foreign keys if you are splitting your database into tables and you are working with a DBMS (e.g. MySQL, Oracle and others). I assume from your tags you are using MySQL.
If you don't use foreign keys your database will become hard to manage and maintain. The process of normalisation ensures data consistency, which uses foreign keys.
See here for foreign keys. See here for why foreign keys are important in a relational database here.
Although denormalization is often used when efficiency is the main factor in the design. If this is the case you may want to move away from what I have told you.
Hope this helps.