How do I write this recursive MySQL procedure? - mysql

I have a MySQL database which contains 2 (relevant) tables: Staff, Supervisors.
Staff contains: StaffID, Name, CostCentre
and Supervisors contains: InstanceID, StaffID, SupervisorID, Obsolete
The Staff table contains all staff in the company, and the Supervisors table links one StaffID (StaffID) to another StaffID (SupervisorID). If we create a new relationship (i.e. staff A no longer reports to staff B, but instead to staff C), then we create a new record and set the original 'obsolete' flag to 'true'.
I have arranged it this way because the Supervisor:Subordinate relationships are subject to change, and are not guaranteed to be correct: We want to be able to change them and maintain an audit trail.
What I need to do is to get a recursive list of CostCentres.
What that means is, say I start with some cost centre. I get a list of all staff who are in that cost centre, and generate a list of all their subordinates. Then I get a list of all those cost centres and repeat for each of those.
I already have a number of procedures, two of which may be relevant:
CALL getCostCentre(iCostCentre) /* get a list of all staff in iCostCentre) */
CALL getSupervisees(iSupervisor) /* get a list of all staff who report to iSupervisor */

I would create a single table containing staff and supervisors, let's call it Employee, and another table for holding relationships (each table with a delete flag field and a change date field for audit trial). The table relationship has a subordinate and a master. And a table for cost centers holding references to the employees. There are some open source CRMs around that you can download (use it maybe) and eventually learn how to structure your db. Regarding cost centers, you can learn from the table Group in standard CRMs

Related

Database design without a 1 column table

I have been working on a database design and I'm stuck hitting a wall. I'm ending up with what I'm reading is not a normalized database structure but I'm having issues trying to find a "more correct" design and if this design is acceptable how do I execute it in Access?
TLDR: If a table with a single column set as an auto number is an acceptable design, how do you go about inserting a record in it using Access?
The segment of the database of concern is creating a structure for storing companies. Requirements for this is that any changes need to be approved by another user and all historical changes need to be captured so that it can be easily reverted also a company can have multiple aliases but only one legal name.
There is three tables in my solution but one of them is a single column table. From what I've read 95% of people on stack overflow all think its a very bad idea but I've found one post were people are that there are cases for it. I think this is not normal also because I can't find a way to just create a new record in a table with only an auto number column (In Access I have not tried others yet).
Table Structure
Company Names : ID, Company ID, Is Legal Name, Created By, Created On, Approved On, Approved By, Event ID, Is Active
(A company could have a few different names known to the public: TD vs Toronto Dominion. Each name is inserted here with a reference to the company it belongs to)
Companies : ID (Auto Number)
(A company exists and this is its ID)
Companies History : ID, Company ID, Market ID, Holding Company ID, Created By, Created On, Approved On, Approved By, Event ID, Is Active
(These are the historical changes that have been made to the company and who did them and who approved them)
Column Notes:
Event ID : is a FK reference to a table holding each record of actions that have either created, updated or deleted records. (User Research using method [y], Typo Fix, ...)
Is Active : Since deleting records is not possible (historical records need to be kept) this column is used to track if this record is to be included in queries.
Options I see and their issues:
I could get rid of the companies table and make Companies History : ID be the new company id but I find that in that case each time I want to update a company I would need to update each FK reference to the previous company id (I don't think this would be a very normalized approach)
Another Option I see is that I get rid of Companies table and use Company Names : ID as the company id and I would add a column to Company Names called Alias of Company ID. I find that solution adds a log of complexity to my stored data where an alias has company information that differs from the entry that was aliased.
Another Option is that I could add the columns: Created By, Created On, Approved On, Approved By, Event ID and Is Active but this would be duplicating information found in the first record for this company in the Companies History table and this isn't adding any real description to this record.
Anther Option is that I make the Companies table a mirror of Companies History and that when I update or insert a record in Companies I would also insert a record Companies History. With this solution I find that again I duplicate information, that newest record in "Companies History" would hold the same information found in last Inserted or Updated record in in Companies
Another option but is to replace the Companies : ID auto number with a short text and I just get the hash of the current timestamp + a random int. I can now insert new records into this table using access but I feel that this is overkill since I just need the exact same functionality as the auto number.
Another option is move only the legal name into Companies table but now when the legal name of a company changes I have no way of tracking this. Also if I want a list of all names I need to use a union on Companies and Company Names. I find that using unions can reduce performances of queries and I use them only when explicitly needed.
If I don't want to duplicate any information and I don't want to update all FK it seems that I need a table with a single column. If this is acceptable how do I go about inserting a record into a table with a single column set to auto number in Access.
If Companies can be derived from CompanyNames (select distinct CompanyId from CompanyNames), there is no point storing again that information. Just replace that table by a view if you want it (but it as little added value).
On the other hand, if CreatedOn refers to the Company creation (not the row creation) then it is obviously a property of the Company, and I would rather work with
Companies --> Aliases.
But of course I don't know the ins and outs of the reality you're dealing with.

Access: Entering multiple subform values with one entry in the form

I've been using Access to create simple databases for a while with great success, but have run into a problem I can't find an answer to.
We ship individualized serialized units to various end-users, and occasionally to resellers that stock them for end-users. I must keep track of which serial numbers end up with each end-users.
The first database I created to handle this recorded company information in one table using their account number as primary key, order information in a second table using the order number as the primary key and linked via the company name, and unit information in a third table with the serial number as the primary key and linked via the order number.
This worked very well until I had to account for these stock orders with a reseller. As it was structured, every unit was linked to one company via the sales order. The issue is that I may ship 20 units on one order to Company A, who then sells 5 to Company B and 3 to Company C.
I realized I needed to link the company name directly to the units, not the orders and have fixed that.
My issue now is simplicity in entering information in the form. My previous database involved the employee in our shipping department merely entering the sales order, selecting the customer name from a drop down menu, then scanning the serial numbers in a subform. This was to ensure simplicity and try to eliminate human error. He had only three things to input, and most of the input was done by scanning barcodes.
As it is currently structured now, the employees out in shipping would have to populate the company name for every record in the subform with the serial number and that complicates things in a way that is unacceptable. At the point of shipping, the company name will always be the same for every unit in the subform.
So.
How would I go about creating a form where the company name is entered once in the form, and automatically populates itself for every record in the subform? The caveat here is that I must also be able to go back occasionally and change the company name of individual units in an order without necessarily affecting the rest of the order. I suppose it starts out as a one-to-many relationship that then must be able to change.
I hope that makes sense.
I have looked for answers using various approaches with auto-fill and relationships and not preserving data integrity, but I feel the answer is just beyond my reach.
The only solution I can think of is to create another field in the unit table for the end-user, and perhaps write a formula that sets this default value as the company name from the order that shipped it. This seems unnecessarily complicated and redundant, there has to be a better way.

What is the best way to associate multiple people to one address in Microsoft Access?

I'm designing a database for my boss in which he wants a list of every dental surgery within a certain area, with every dentist at said surgery listed.
What would be the best way to go about this?
I'm leaning towards having a seperate table that contains only dentist names, since having them all in one table would get overcrowded/confusing.
The only problem with this is that he wants to be able to look at the screen and see everything laid out in this format:
Dental Practice_________Dentist name__________ Address________Phone number_______etc
____________________________Dentist name
____________________________Dentist name
_________________________Dentist name
Can this be achieved in table view or would I have to create two separate tables and link them together on a report to show him?
Store the addresses in one table, store the names in another table, create a junction table to show which dentist belongs with which address. create a form to show the information. You will need the junction table, because I think you will find that some dentists operate from more than one address.
Address table
AddressID
etc
Dentists
DentistID
etc
DentistAddresses
AddressID
DentistID
As long as your tables are properly indexed, you can create a query that will form the basis of the form to show the data. You should also consider subforms, the layout you illustrate is a form/subform set-up in MS Access. The address would be in the main form and the dentist list in the subform, which would be based on the junction table.
Just be very careful about changing addresses. The user cannot edit address, they must create a new address.
Well, what you will need is a single table that lists areas.
Table:
Areas
- AreaID
- AreaName
and a table for the Dentists which references the Areas Table by FOREIGN KEY
Dentists:
- DetistID
- DentistName
- DetistContactNumber
- AreaID
This will allow you to write a query something like
SELECT *
FROM Dentists d INNER JOIN
Areas a ON d.AreaID = a.AreaID
to retrieve the results you are looking for.

Updating Table But Keeping One Existing Data

I'm working on these tables:
staff(staffID, staffName, branchID, address, phone, lastUpdatedDate)
branchRef(branchID, branchName)
To generate report on staff details categorised by branch
SELECT staffID, staffName, staff.branchID, address, phone, lastUpdateDate, branchName
FROM staff, branchRef
WHERE staff.branchID=branchRef.branchIC
For example what if, John is in Branch01 in year 2011 and Branch03 2012. How do preserve the (Branch01, 2011) when updating to (Branch02, 2012). I've read that using trigger to do the job, trigger involves in almost all of the fields but I only wish to keep a record of the old branchID. Is there any suggestion to this problem? Thank you!
Currently, you have a one-to-many relationship: One staff member has one branch, but one branch has many staff members.
If a staff member will now be able to be part of more than one branch (even as history, as you said in your comment), then the relationship will become a many-to-many relationship. Apart from that I think you want to get the other branches in order so what you could do is the following:
Keep your current tables just as they are, but removing branchId from staff:
staff(staffID, staffName, address, phone, lastUpdatedDate)
branchRef(branchID, branchName)
Create a new table staff_branches that will hold the relationship between them:
staff_branches(staffID, branchID)
The primary key of the table will be both fields. Now you should implement an order of those tables. If you just care about the order, just add an integer field that would hold that order (1, 2, etc). If you want to get additional information (like the date in which the staff member started in that branch), just use a date for the orderField:
staff_branches(staffID, branchID, orderField)
Once you've done that, you can query for the current branch for an employee by searching in that table for the branch with the max(orderField) for that staffId.
It sounds like you need to update your data model.
It doesn't take into account the possibility that a staff member might switch branches.c
Triggers won't help you with this problem.
You could:
make a new table staff_member_works_in_branch, with fields like start_date and end_date, staffId and branchId to represent the new m:n relationship. Your report may have to be updated. (recommended solution if you're going to be doing this often)
keep the records of moved staff members data outside of the database
implement a kludge with "fake" employee rows (not recommended)

Resolve many-to-one, child before parent table problem

In my program, I need to make an organization chart starting with individuals and grouping them under a manager, then group those managers under senior managers etc... How do I do this with regards to the database?? This is a many to one relationship - which I thought was illegal and impossible - and would be like starting with the child table - individuals - before creating its parent - manager.
If someone can help point me in the right direction to design my database I'd really appreciate it!!
----EDIT----
Here's a more detailed explanation of my problem:
Let's say a user of my program starts by entering in 35 individuals they'd like to use on some project they're going to work on. Now, there are several possible management positions that can be created and have employees/other (lower) managers assigned to those. The user doesn't HAVE TO create any particular position, but can pick and choose and assign however they like. The only constraints are there will always be a top manager - let's call him the President - and that he SHOULD (but doesn't HAVE TO) only assign 5-10 people to any given manager (president included). So in this example we are starting with 35 individuals and a President. Now we start grouping the 35 individuals into teams and assigning one of them as manager. Say the user decides to have two teams of 6, two teams of 9, and one team of 5 - each of these groups has one of its individual members assigned as manager of that team. So now we have 5 teams, each under its own manager, and those five managers would now be assigned to the President. The program would let this go but warn the user that the number of individuals under a manager in the last team is less than 5 (is only 4). So the user can now (or at ANYtime) go back and change the organization. So let's say he wants to fix this issue and changes up the teams. So he breaks up one of the two teams of 9 and assigns one individual to the team that was short a person. This makes a final count of 3 teams of 6 (5 individual members and one manager), one team of 9 (8 ind and 1 mngr), and one team of 8 (7 ind and 1 mngr) and all 5 team managers are assigned to the president.
Only in real life this can get broken down much further - nests with many more levels of management. How can I do this?
Is Joe Hopfgartner's answer below still valid? Can I just make a "role" column, even though the role would be assigned later (after the row is initially created)? Or changed at any time? Can this self-referencing foreign key be null? (as it would be in the case that no manager has been assigned yet) Or should I move the individuals to a separate "team" table after they've been assigned to a team and move the managers to a "manager" table once they've been assigned as a manager, then add a foreign key for the team table referencing the manager table?
Also, I am using MySQL, so does that fact that you cannot use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL operations affect my particular case (since users will no doubt often be changing the assignments)?
Thank you so much for helping me with this!!!
if one individual can only have one manager, just introduce a "parent person" id field or put managers in a seperate table.
if not, create another table for a relation like "person_has_manager" that assigns a person to a manager.
you can also put managers and persons into the same table and introduce a "role" field, but this can be tricky when using foreign key constraints if you want to ensure that only manages can have persons assigned to them.
to solve this problem you can introduce a "person_is_manager" table that links person to their job as manager, and persons can be linked to be managed by that manager. this ould look like this:
persons
-> person_id (primary)
-> name
-> etc
managers
-> person_id (primary, linked to person_id in persons)
person_has_manager
-> person_id (primary)
-> manager_id (primary, linked to person_id in managers table)
It's a tree. You can use a single table with a parent_id field, to indicate which record is the parent to the current one.