Entity Relation Design - oracle

I am trying to implement an entity relation for a hospital oracle database system.
I am rather confused if I should seperate the table below or merge them into 1.
- Supply
ItemNo (PK) , Name, ItemDescription, QuantityInStock, BackOrderLevel, CostPerUnit
- PharmaceuticalSupply
DrugNo (PK) , Dosage, MethodOfAdmin
Basically in my ERD, I pointed PharmaceuticalSupply to Supply as a subset which inherits the attribute but also have additional attributes. Am I wrong in doing that?

Ultimately, this is a design decision that has no right or wrong answer, but keeping them separate can be helpful. For example, there are many types of supplies that are not pharmaceutical. If you merge the tables, you make it possible to enter data that has no real meaning. For example, you can't have a dosage of bandages. The separate table makes it clear that dosage only applies to pharmaceuticals.
Note that there are a few variations on how to manage the PKs and FKs in PharmaceuticalSupply. It could have both an ItemNo and a DrugNo, where ItemNo is a foreign key. In that case, either one could be the primary key, but if DrugNo is the primary key, then ItemNo probably needs to be a unique index. However, unless DrugNo is needed due to some custom format, it might work well to simply use ItemNo as both PK and FK and completely eliminate DrugNo. This results in a "specialization" as the relational database world likes to refer to it.

It depends on your population. It it's a subset, to reduce redundancy add a foreign key to Supply. That way you'll be able to build a join that list all data.
I would still introduce a DrugNo key for indexing. Can an item number appear more than once in the PharmaceuticalSupply table ? If your do then your definitely need the DrugNo key.
PharmaceuticalSupply
DrugNo (PK) , ItemNo (FK), Dosage, MethodOfAdmin

Related

Validate that value is unique over multiple tables access

Scenario: I have to create a database which has to contain 3 different tables holding information about people. Lets call them Members, Non_Members and Employees. Among the other information they may share , one is the telephone number. The phone numbers are unique, each in its respective table.
My problem: I want to make sure the phone number is always unique among these 3 tables. Is there a way to create a validation rule for that ? If not and I need to redesign the database, which would be the recommended way to do it.
Additional info: While the 3 tables hold the same information (Name , address etc.) its not required always required to fill them. So I am not sure if a generic table named Persons would work for my case.
Some ideas: I was wondering if and how I can use a query as a validation rule (that would make things easier). If I would end up creating a table called Phone numbers , how would the relations between the 4 tables would work in order to ensure that each of the 3 tables has a phone number.
ERD
I assume you are talking about a relational database.
I would go for a single person table with a "type" column (member, non_member, ...). That is much more flexible in the long run. It's easy to add new "person types" - what if you later want a "guest" type?
You would need to define as nullable to cater for the "not all information is required" part.
With just a single table, it's easy to make the phone number unique.
If you do need to make it unique across different tables, you need to put the phone numbers in their own table (where the number is unique) and the references that phone_number table from the other tables.
Edit
Here is an example of creating such a phone_number table:
create table phone_number
(
id integer primary key,
phone varchar(100) not null unique
);
create table member
(
id integer primary key,
name varchar(100),
... other columns
phone_number_id integer references phone_number
);
The tables non_member and employee would have the same structure (which is a strong sign that they should be a single entity)
Edit 2 (2016-01-08 20:12)
As sqlvogel correctly pointed out, putting the phone numbers into a single table doesn't prevent a phone number to be used by more than one person (I misunderstood the requirement so that no phone number should be stored more than once)

Changing Primary Key in Oracle

I'm updating a table that was originally poorly designed. The table currently has a primary key that is the name of the vendor. This serves as a foreign key to many other tables. This has led to issues with the Vendor name initially being entered incorrectly or with typos that need to be fixed. Since it's the foreign key to relationships, this is more complicated than it's worth.
Current Schema:
Vendor_name(pk) Vendor_contact comments
Desired Schema:
id(pk) Vendor_name Vendor_contact comments
I want to update the primary key to be an auto-generated numeric key. The vendor name field needs to persist but no longer be the key. I'll also need to update the value of the foreign key on other tables and on join tables.
Is the best way to do this to create a new numeric id column on my Vendor table, crosswalk the id to vendor names and add a new foreign key with the new id as the foreign key, drop the foreign key of vendor name on those tables (per this post), and then somehow mark the id as the primary key and unmark the vendor name?
Or is there a more streamlined way of doing this that isn't so broken out?
It's important to note that only 5 users can access this table so I can easily shut them out for a period of time while these updates are made - that's not an issue.
I'm working with SQLDeveloper and Python/Django.
The biggest problem you have is all the application code which references VENDOR_NAME in the dependent tables. Not just using it to join to the parent table, but also relying on it to display the name without joining to VENDOR.
So, although having a natural key as a foreign key is a PITN, changing this situation is likely to generate a whole lot of work, with a marginal overall benefit. Be sure to get buy-in from all the stakeholders before starting out.
The way I would approach it is this:
Do a really thorough impact analysis
Ensure you have complete regression tests for all the functions which rely on the Vendor data
Create VENDOR_ID as a unique key on VENDOR
Add VENDOR_ID to all the dependent tables
Create a second foreign on all the dependent tables referencing VENDOR_ID
Ensure that the VENDOR_ID is populated whenever the VENDOR_NAME is.
That last point can be tackled by either fix the insert and update statements on the dependent tables, or with triggers. Which approach you take will determine on your application design and also the number of tables involved. Obviously you want to avoid the performance hit of all those triggers if you can.
At this point you have an infrastructure which will support the new primary key but which still uses the old one. Why would you want to do this? Because you could go into Production like this without changing the application code. It gives you the option to move the application code to use VENDOR_ID across a broader time frame. Obviously, if developers have been keen on coding SELECT * FROM you will have issues that need addressing immediately.
Once you've fixed all the code you can drop VENDOR_NAME from all the dependent tables, and switch VENDOR_NAME to unique key and VENDOR_ID to primary key on the master table.
If you're on 11g you should check out Edition-Based Redefinition. It's designed to make this sort of exercise an awful lot easier. Find out more.
I would do it this way:
create your new sequence
create table temp as select your_sequence.nextval,vendor_name, vendor_contact, comments from vendor.
rename the original table to something like vendor_old
add the primary key and other constraints to the new table
rename the new table to the old name
Testing is essential and you must ensure no one is working on the database except you when this is done.

Should I store US states as an array or create table columns?

I have an app that houses product data via a Product model and table. Each product has specific state availability (multiple states) that I will need to filter and/or search by in the future. I am hoping to find someone who can tell me the most efficient way to store this data. As I see it, I have two options.
The first is to simply create 50 columns in my table, titled with each state name and containing a boolean value. I can then simply filter by = "avail in California" if product.ca. While this certainly works, it seems a bit cumbersome, especially when searching for multiple state availability.
The second option would be to simply have one column("states") that stores an array of available states and then filter by = "avail in California" if product.states.include? "CA". This seems like a better solution for two reasons. The first, it just allows for a cleaner DB table. Second, and more important, I can allow my user to search by simply saving the user's input as a variable(user_input) and then = "avail in California" if product.states.include? user_input. This solution does call for a little more work up front however when saving the product in the DB, since I won't be able to simply check off a boolean value.
I think option two makes the most sense, but am hoping for some advice as to why or why not. I have found a few similar questions, but they do not seem to explain which solution would be better, just how to accomplish each.
What should I do?
You should normalize unless you have a really good reason not to, and I don't see one in your overview.
To normalize, you should have the following tables:
product table, one record per product
state table, one record per state
product_state table, one entry for every product that is in a state
The product_state schema looks like this:
(product_state_id PK, product_id FK, state_id FK)
UNIQUE INDEX(product_id,state_id);
This allows you to have a product in zero or more states.
I assume that since you’re selling products, you will be charging taxes. There are different taxes by state, county, city. There are country taxes in some countries too.
So you need to abstract these entities into a common parent, usually called GeopoliticalArea, so that you can point a single foreign key (from, say, a tax rates table) at any subtype.
create table geopolitical_area (
id bigint primary key,
type text not null
);
create table country (
id bigint primary key references geopolitical_area(id),
name text not null unique
);
-- represents states/provinces:
create table region (
id bigint primary key references geopolitical_area(id),
name text not null,
country_id bigint references country(id),
unique (name, country_id)
);
insert into geopolitical_area values
(1, 'Country'),
(2, 'Region');
insert into country values
(1, 'United States of America');
insert into region values
(2, 'Alabama', 1);

Are there any reason to use both primary key and unique key together on the same field?

I am analyzing an Oracle database design and I am perplexed at seeing both unique keys and primary keys on the same fields. These unique-primary key pairs are consistently created on all tables. I see no reason to do this.
If I have a primary key anyway, is there a good reason to create an additional unique key on the same field?
For a table resolving a many-to-many it would be common to have a two part key (as indicated by Quassnoi). It is also quite likely to need indexes supporting access through either parent.
If you have, for example, PERSON, ADDRESS and PERSON_ADDRESS tables, your PERSON_ADDRESS table may have the primary key of (PERSON_ID, ADDRESS_ID) and a supporting index. You would also have another index on (ADDRESS_ID,PERSON_ID), and you would likely make this a UNIQUE index (as it is a unique combination of fields).
It is also possible that your DBA has some particular way of generating tables that starts with a UNIQUE index on the primary key fields followed by the creation of the PRIMARY KEY constraint. That may show up in some GUI tools in the way you suggest.
No, there is no reason to have it also as unique; when you set a column as PK you are sure that:
No NULL will be accepted for that column on INSERT or UPDATE;
Values in the whole table for that column are always UNIQUE;
so just PK is enough. Since there is a UNIQUE index for the PK column, by definition, there is no need to add any other index on that column only because queries will use the PK index whenever only that column is affected.
I believe it's impossible (PK and unique constraint on the same column[s])...
You cannot designate the same column or combination of columns as both a primary key and a unique key.
(from here, section "Restrictions on Primary Key Constraints"). Isn't it?
Oracle won't let you create multiple UNIQUE and PRIMARY KEY constraints on the same field set in the same order and will fail with ORA-02261.
If you have composite keys, you can create PRIMARY KEY on the column set in one order (PRIMARY KEY (a, b)) and a unique constraint on another (UNIQUE (b, a)).
This will parse and execute, however a single index will be used to police both constraints so it makes no sense.
Could you please post the table scripts?
Just a little theoretical background here... When modeling your table, you identify a set of keys. These keys are logically equivalent, but for practical purposes you pick one of them and call it "primary" while the rest of them become "alternate".
(In DDL SQL, a primary key is called "PRIMARY KEY", while "alternate key" is called "UNIQUE constraint".)
So, in light of that, your question is equivalent to: "is there a good reason to have two identical keys", and the answer is: "no".
That being said, you may have overlapping keys (i.e. keys that share some fields but not all), but this is usually a sign of a bad design... and the answer is: "probably not".
OTOH, if by "unique key", you actually mean "unique index", then yes, you need both of them.
Index is not a logical constraint - it is there just to allow a logical constraint such as PRIMARY KEY to perform well (and for querying, but that's a different topic).

Surrogate key in 'User' / 'Role' tables for desktop app? Whats the purpose?

I have to add some security for a C#/.NET WinForms/Desktop application. I am using Oracle DB back-end.
The tables are simple: User (ID,Name), Role(ID,Role), UserRole(UserID,RoleID).
I am using the windows account name to populate User table. Role table will for now just be simply 'Admin','SuperUser','BasicUser'...
Since no two people could ever possible have the same windows account name... even when I do not control these name management (netops does, hence why I want to use windows accounts so I don't have to manage it ;)). For Role table, I should again never have dupe value - I control the input, there will only be 3 (tactical app going away within year). UserRole is a join table to represent the Many-To-Many relationships of users and roles, so no surragate key is justified.
Simple question - Why bother with 'ID' (int) in the User and Role table? Any point or advantage here? Is this one of those 'I've always done it this way' type things? Or have I just not done this in awhile and forget the reason?
Names change - primary key values must not. Abigail Smith becomes Abigail Jones and the username changes but a surrogate key protects against having to cascade those changes everywhere.
If you are using a surrogate key but there is a column or combination of columns which should be unique, then enforce that using a unique index. There's a good chance you'll want indexes on your user.name and role.role columns anyway, and a unique index is more space efficient and supplies useful metadata to the optimizer. If you have a surrogate key but don't have another combination of columns that uniquely identify a row then think again whether you have your entity definition right.
One caution. Especially for very narrow tables with few access paths, you may use an index-organized table. Oracle will only allow an index organized table on the primary key, but does allow foreign keys against a unique set of columns (if it is enforced by a unique constraint, not simply a unique index).
It is possible that you'll end up with a table where a unique ID is enforced through a unique index and treated as PK by an ORM and used as the parent for foreign key relationships, but the primary key (as defined in the DB) is the rolename/username/whatever because you want that as the driver for an index-organised table.
A surrogate key is not required on intersection tables, but here are a few reasons to do so:
Consistency: If every table has a single artificial key, you always know the key name when you know the table name.
Ease Of Use: Less typing — one key means ON and WHERE clauses are shorter and thus less error-prone.
Interoperability: Some ORMs only work well with tables with a single primary key column.

Resources