I am currently developing a new database / web application for our school. I will need to supply a little bit of background information to make my question a little more relatable.
There are many different user types that will access this application each needing to access different parts of the application with different permissions for each “zone” they may be able to access.
For example:
A student can login and access there information and update their details as well as download copies of their reports (so they can only see their information)
A teacher can login and access there information and all the students they teach
A manager can login and access there information and all the teachers and students they manage
There are then a bunch of other login types however for this question they are not really important as they are all technically just more users which do not have or require their own table for extra information.
I have for the most part decided on a structure that I am happy with, however I keep changing my mind on how I think the following is best done.
I have a user table (User_T) where all the relevant user information is stored, (username, password, etc.)
However I also have separate tables for some of the user types (EG, Student, Staff, ETC), this is necessary because a student needs to have different information stored than a staff member.
Here is where my problem lies, all of the users will have some of the same basic fields (First name, Last name, Birthdate, Gender, etc.).
Should I store these in the User_T table? Or in the individual tables?
If I store them all in the User_T table this makes it easier to have the application pull their information and allow them to update, on the down side when displaying student details for example, I will need to reference the User_T to get the students name etc.
I am currently in the mindset that the best option is to have the separate tables with all the fields and join them in a view User_V, with a field that indicates the origin of the data so that when an update is preformed it can be applied against the appropriate table.
Thoughts?
Sounds like there would be good separation by using the User_T table as the general "people" profile table and the other tables for the unique role specific data. User_T would store the more general info about the person and the ID in this table would be perhaps a Foreign Key called "person_id" in the other tables.
Going with this table schema would also depend on how often you might query this shared general data together. For example, if you plan to search a name or email without knowing the type/role (whether staff, student, etc), then it is good to have this general people information in the User_T table apart from the other information. If you knew the role/type, you could choose the corresponding table to search in and simply JOIN as needed for the User_T data. But if you don't separate your tables this way, then you are left with using a VIEW or UNION to allow you to search on only those general columns with a single query, which in my opinion is much more troublesome to optimize.
User_T table: id, first_name, last_name, email, gender, birthdate, role, ...
Students table: id, person_id, gpa, ...
Staff table: id, person_id, staff_type, hire_date, ...
Related
I do not have much experience and I would like to know if there is an easy way to create user rights and privileges, so that each user can access only specific records from the database tables, based on the level he belongs to.
More specifically, suppose we have a group of companies where this group has some companies and these companies have some branches and the branches have some users.
I want the user belonging to the "group of companies" level to have access to and view all the entries in the database related to that group and what is below it (its companies and the branches of these companies).
The user who belongs to the "company" level should have access and see only the files of this company and the branches that this company may have in the database.
The user belonging to the "Branch" level should only be able to access and view this barnch records in the database.
And finally the user belonging to the "End User" level to have access and see only the records created by the user in the database.
Of course level "administrator" will have access to all records in the database.
I thought of creating a user table with a field "User_Level" and in each table to enter USER_ID where based on this I can find the level of a user but how can I restrict access based on the Group of Companies or the Company or the Branch where it belongs?
In APEX you can create authorization schemes to determine what components a user has access to within an application - but that is just a part of the answer to this question. Your question is about filtering the data that is showed to a user based on certain criteria.
There are a couple of possible solutions to this. Since this is a very broad question I'm just going to give you pointers/concepts to start your research. Up to you to determine what solution/combination is most suitable for your implementation.
Concept: Multi-Tenancy
If the data is used by multiple tenants then add a tenant_id to each table that has tenant specific data. In your case a tenant should be a branch. A simple design could be a groups table (to hold branch - companies - company groups), a group_members table (to define relationship between branch - companies - company groups OR between any group and a user) and a users table.
Concept: VPD This is a feature in the oracle database that allows a transparent implementation of security rules. In the application you'll define a simple select like
SELECT * FROM emp
But the VPD implementation will automatically add a where clause to the query to only show the records defined in the VPD policy. This makes developing the application a lot easier since there is less room for errors. Note that this database option could not be included for your licence. There is also something called "Poor Man's VPD" that does not use the VPD option. Google on how to implement this in your apex application.
Just do it all by hand: This is the least preferred option but it can be done. For every component where a select is done, manually add a where clause to restrict the returned rows. However this is very maintenance intensive and there is a ton of room for errors - obiously the data model will still have to support the striping of the data.
This blog post by Jeffrey Kemp might give you some pointers as well: https://jeffkemponoracle.com/2017/11/convert-an-apex-application-to-multi-tenant/ - go through the "further reading" section at the bottom.
you can create a procedure or function and in your app's shared components -> authorization scheme use that such as pl/sql function/procedure returning boolean and return true for the users you want to see the things and false for hiding.
In Apex components, select this authorization scheme like in items, pages etc.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I need a Database to store the following information :
User : FirstName, LastName, Email, Mobile, About/Description, Type (Staff/Freelancer/Client)
Staff : Type (Designer/FE Developer/BE Developer/DB Developer/SE Optimist), Rank of Staff
(Manager/Staff/Employee), Projects worked on, Active Projects working on, Address,
Skills (HTML/CSS/JS/ASPX/PHP/DB Development/SEO/Design),
Software(Photoshop/Illustrator/In-Design/Fireworks/VisualStudio/MSQL/Wordpress)
Freelancer : Type (Designer/FE Developer/BE Developer/DB Developer/SE Optimist), Projects worked on, Active Projects working on, Address, Skills (HTML/CSS/JS/ASPX/PHP/DB Development/SEO/Design), Software (Photoshop/Illustrator/InDesign/Fireworks/VisualStudio/MSQL/Wordpress)
Client : Projects Owned, Active Projects owned, Address (Home/Work/Invoicing/Delivery)
Address : House No:, Street Address, Line 2, Line 3, County, Country, Postcode, Landline
Project : Title, Client Name, Start Date, End Date, Due Date, Status (Active, Hold, NotActive), About, Development Team (List of Freelancers or Staff working on the Project), Progress (done by Milestones : Design/FE/BE/DB/BO/SEO/Deployment)
Basically the thing I'm struggling on is how to link the different type of Address and Users etc. For example a User can be : Staff or a Freelancer or an Client, Or a staff or freelancer can also be a client. I have no idea how that would work in Database Format. The same goes for Address Types etc.
Any Help ? I'm really Stuck. Thanks in Advance.
You're asking about the basics of RDBMS design. It's sometimes called Entity-Relationship design. It's a big topic. You may want to read a book on it.
It sounds like you need a Person table with a row describing each unique person in your system.
You then need, perhaps, an Organization table with a row describing each organization (company, consultancy, freelance entity, customer, provider, etc).
A Person_Organization table could relate persons to organizations. This would implement a many-to-many entity relationship between Person and Organization. This table could contain PersonID, OrganizationID, and a field describing that person's role in that organization.
You could add a Contact table with contact information (addresses, tel nos, email, etc). It would contain a Person id in each row.
You'd have Project table with a row for each project. This would contain an OrganizationID that identified the single customer for it, as well as other material describing the project.
There'd also be a Role table with a role for each Organization playing a role in each project.
How to handle an Organization that has more than one contact address is an exercise left to you.
Please keep in mind that "too clever is dumb" in this kind of work.
You do all of this using the concept of a foreign key.
Generally, a good idea is to give each table a primary key column that will serve as an identifier for each row of data. User table would have UserId, Project table would have ProjectId, etc.
From there, you add foreign key constraints to columns in your other tables that forces those rows to map to a User. For example, your Address table would have a column called UserId that is foreign key to the User table; this key tells you that the address of that row belongs to the corresponding User.
How to build the foreign key constraints depends on your requirements and the relationships between your data; it's something that you should figure out so that you will be able to access all of the necessary information using simple queries.
Also, keep in mind that your data is hierarchical. You have a Client, Freelancer, and Staff, each of which needs an address. But all of these 3 are also users. It makes much more sense to key each of those tables to the User table, and then key the Address table to the User table as well. This allows for your relationships to be more flexible and easier to understand.
I'm fairly new to Access.
I have a DB table that needs to be normalized. I have some information about a person. These people are authorized to grant access to areas at our work site. Every person may be authorized several times to manage different areas, and of course different people can be authorized to manage different areas. My first try at it was to include the authorization and the areas together, but I realized that I was really repeating the data that way. After doing some study I decided that the best way to do this was to create 4 tables
tblPerson, tblPermission, tblArea, tblArea_Permission
The tblArea_Permission is a join table for the many-to-many relationship between tblPermission and tblArea (this is something that I just learned about). I seemingly set up the table relationships OK on the relationship tab. I also use a query for adding the records to the join table. When I try to do this, with a query that is getting the records from the tables, I get "You cannot add or change a record because a related record is required in table XXX." This would seem to be impossible.
I decided that I could probably live with the DB not enforcing referential integrity and took that away and used a combined primary key for the two records because every person with permission will control an area in only one combination. That seemed to work, but then I noticed that the records would randomly change. I decided that the DB must be corrupt. Parts of the DB seem to be working correctly, so I started with a new database and imported the tables and one form, then started to rebuild the new tables as described above. I got the same error.
Any help would be greatly appreciated. I've read through some different books, and used google, but nothing addresses this.
If a person is authorised to manage an area, you need a persons_area table:
PersonID ) Primary key
AreaID )
Which shows which areas the person can manage. I am not sure where the permissions table is coming from.
You will then not be able to add a record to person_areas table unless you have an ID in the area table and an ID in the persons table. If either of these IDs are missing, you will get the error above.
If you want more relevant comments on your DB design, you will need to post schemas.
I'm building a website that will be used by employees to log work that they've completed. The site contains a page to submit the information, a page to view the information and a page with the employees personal info like name, email, phone, etc. I'm using ASP.NET Membership for authentication. All code will be VB. My questions:
1) ASP.NET Membership only stores the username and email of members. I want to store additional information like first and last name, phone number, etc. Can I just update the tables in the membership database to include this information? Or should I store this information in a separate database? My goal is to populate text boxes on one of the pages with data specific to the user that is currently logged in.
2) The work completed will be stored in another database since it seems logical to keep it separate from membership data. What is the most efficient way to pull and display records from this separate "work" database that are specific to the user who has logged in and been authenticated against the member database?
3) I'm having trouble with the design of tables for the "work" database. Each record stored in the database will represent a days worth of work. However, a number of activities will occur during that day. Each activity will have a type of activity, location and amount of time worked. An employee can complete 1 activity or 100 activities. I assume I'm going to need a table just for the activities and then relate it to the work table. Does this sound correct?
For your first Point i will suggest you to create your own table of User and relate this table with membership user table with guid viz. keep on userid file in your table and relate it with membership table.
Second point will automatically get solved once you will create your own user table, all you need is to relate work and user table(created by you) to fetch the records from work
And at last if you are creating new table for activities how come you will relate it to your work table, again you will have multiple occurrence for record, instead i would suggest do not create another table for activities keep it in work table itself as if you are creating a new table, you will have to provide relationship with work which will result in redundancy.
Hope this helps.
I am planning to create a website using ASP.NET and SQL Server. However, my plan for the database design leaves me wondering if there is a better way.
The website will serve as a repository of information for various users. I figure I would have two databases, a Membership and Profile database.
The profile database would contain user data for all users, where each user may have ~20 tables. I would create the tables when the user account is created and generate a key used to name the tables. The tables are not directly related.
For Example a set of tables for two different users could look like:
User1 Tables - TransactionTable_Key1, AssetTable_Key1, ResearchTable_Key1 ....;
User2 Tables - TransactionTable_Key2, AssetTable_Key2, ResearchTable_Key2 ....;
The Key1, Key2 etc.. values would be retrieved based on the MembershipID data when the account was created. This could result in a very large number of tables over time. I'm not sure if this will limit scalability by setting up the database in this way. Any recommendations?
Edit: I should mention that some of these tables would contain 20k+ rows.
Realistically it sounds like you only really need one database for this.
From the way you worded your question, it sounds like you're trying to dynamically create tables for users as they create accounts. I wouldn't recommend this method.
What you want to do is create a master table that contains a primary key for each individual user. I'm assuming this is the Membership table. Then create the ~20 tables that you need for the profiles of these members. Every record, no matter the number of users that you have, will go into these tables. These 20 tables would need to have a foreign key pointing to the unique identifier of the Membership table.
When you want to query a Member for their user information, just select from the tables where the membership table's primary Id matches the foreign key in the profile tables.
This would result in only a few tables in the end and is easily maintainable and follows better database design.
Your ORM layer (EF, LINQ, DAL code) will hate having to deal with one set of tables per tenant. It is much better to have either one set of tables for all tenant in a single database, or a separate database per tenant. The later is only better if schema upgrade has to be vetted by tenant (like Salesforce.com has). If you can afford to upgrade all tenant to a new schema at once then there is no reason for database per tenant.
When you design a schema that hold multiple tenant the important things to remember are
don't use heaps, all tables must be clustered index
add the tenant ID as the leftmost key to every clustered
add the tenant ID as the leftmost key to every non-clustered index too
add the Left.tenantID = right.tenantID predicate to every join
add the table.TenantID = #currentTenantID to every query
These are fairly simple rules and if you obey them (with no exceptions) you will get a perfect partitioning per tenant of every query (no query will ever ever scan rows in a range of a different tenant) so you eliminate contention between tenants. To be more through, you can disable lock escalation to make sure no tenant escalates to block every other tenant.
This design also lends itself to table partitioning and to sharing the database for scale-out.
You definitely don't want to create a set of tables for each user, and you would want these only in one database. Even with SQL Server 2008's large capacity for tables (note really total objects in database), it would quickly become unmanageable. Your best bet is to use 20 tables, and separate them via a column into user areas. You might consider partitioning the tables by this user value, but that should be tested for performance reasons too.
Yes, since the tables only contain id, key, and value, why not make one single table?
Have the columns:
id, user ID, key, value
Put an Index on the user ID field.
A key idea behind a relational database is that the table structure does not change. You create a solid set of tables, and these are the "bones" of your application.
Cheers,
Daniel
Neal,
The solution really depends on your requirement. If security and data access are concern and you have only a handful of users, you can set up a different db for each user with access for him set to only his/her database.
Other wise, what Daniel Williams suggested is a good alternative where you have one DB and tables laid out with a indexed column partitioning the users data rows.
It's hard to tell from the summary, but it looks like you are designing for dynamic attribution by user. This design approach is called EAV (Entity-Attribute-Value) and consists of a simple base collection key (UserID, SiteID, ProductID...) and then rows consisting of name/value pairs. In a more complex version, categories are sometimes added as "super columns" to the tuple/row and provide sub-groupings for a set of name/value pairs.
Designing in this way moves responsibility for data type integrity, relational integrity and tuple integrity to the application layer.
The risk with doing this in a relational system involves the breaking of the tuple or row into a set of rows. Updates, deletes, missing values and the definition of a tuple are no longer easily accessible through human interaction. As your application evolves and the definition of a tuple changes, it becomes almost impossible to tell if a name/value pair is missing because it's part of an earlier-version tuple or because it was unintentionally deleted. Ad-hoc research as well becomes harder to manage as business analysts must keep an understanding of the virtual structure either in their heads or in documentation provided.
If you are looking to implement an EAV model, I would suggest you look at a non-relational solution (nosql) like MongoDB or CouchDB. These stores allow a developer to save and retrieve "documents" or json-formatted messages that are essentially made up of a collection of name/value pairs and can look very much like a serialized object. The advantage here is that you can store dynamic attribution without breaking your tuple. You always know that you have a complete tuple because you can store and retrieve it as a single "blob" of information that can be serialized and deserialized at-will. You can also update single attributes within the tuple, if that's a concern.
MongoDB also provides some database-like features such as multiple-attribute indexes, a query engine that is robust in comparison to other similar non-relational offerings and a sharding solution that is much less trouble than trying to do it with MySQL.
I hope this helps.