Flag column or foreign key? - sql

I have ENTERPRISES and DOMAINS table. The property of each enterprise is that it should have a single primary domain, but it can have more than one domain. I have come up with this table structure
+---------------------------------------+
| ENTERPRISES |
+----+--------------+-------------------+
| ID | Name | Primary Domain ID |
+----+--------------+-------------------+
| 1 | Enterprise A | 2 |
| 2 | Enterprise B | 4 |
+----+--------------+-------------------+
+---------------------------------------+
| DOMAINS |
+----+------------------+---------------+
| ID | Domain Name | Enterprise ID |
+----+------------------+---------------+
| 1 | ent-a.com | 1 |
| 2 | enterprise-a.com | 1 |
| 3 | ent-b.com | 2 |
| 4 | enterprise-b.com | 2 |
+----+------------------+---------------+
My co-worker suggested this alternative structure:
+-------------------+
| ENTERPRISES |
+----+--------------+
| ID | Name |
+----+--------------+
| 1 | Enterprise A |
| 2 | Enterprise B |
+----+--------------+
+----------------------------------------------------+
| DOMAINS |
+----+------------------+---------------+------------+
| ID | Domain Name | Enterprise ID | Is Primary |
+----+------------------+---------------+------------+
| 1 | ent-a.com | 1 | False |
| 2 | enterprise-a.com | 1 | True |
| 3 | ent-b.com | 2 | False |
| 4 | enterprise-b.com | 2 | True |
+----+------------------+---------------+------------+
My question is, which one is more efficient/correct?
Also, in the first example should I use ID for primary domain column or a string value, so ENTERPRISES table does not have a circular dependency on DOMAINS table?

Both are correct. But go for the FK.
The one you suggest has less sparse data, while in the second example you may have 100 domains belonging to the same company, all with IsPrimary set to False and just one domain set to True.
Also, it's easier to enforce exactly one primary domain in the first scenario, while in the second you'll have to write a trigger or a check in your code to see that there is one, and only one, primary domain at all times.
Again, stick to the FK.

Circular references are OK. Circular dependencies are not. As long as Primary Domain ID is nullable, then you're fine. Otherwise you'll have a chicken-or-the-egg scenario, being unable to create a Domain without an Enterprise, but also unable to create an Enterprise without a Primary Domain ID.
I would choose the former (your proposed solution), because you're defining a one-to-one relationship. While the Enterprise->Domain relationship is one-to-many, the Enterprise->Primary Domain relationship is one-to-one.

In the first model you say an Enterprise should have a single primary domain. Expand that a moment and say it will have a single primary domain. At this point you'd be inclined to mark that column as not nullable.
The problem then is you won't be able to insert data since you've created a circular depedancy. You can't insert an enterprise without a domain and you can't insert a domain without an enterprise.
I prefer the first model as it is cleaner and more explicit. Your model enforces that there is a single primary domain where there is nothing in the second model so you'd be forced to enforce this rule using some other mechanism.

Related

RDBMS: Generating a locally Unique Key for a Relational Table with Foreign Key

Below is the schema of the database.
There are multiple screenplays each identified by a globally unique key.
Multiple scenes can exist for a screenplay and linked by foreign key.
The obvious choice for me for scene_id of Scene table was to use an auto-increment Integer field type which will ensure each scene in Scene table has a globally unique key across all the multiple screenplays.
Now, the query is:
What is the best way for generating scene_id for Scene table?
Isn't keeping a globally unique key an overkill when the
scene_id needs to be unique only within a particular Screenplay?
A sample table
+----------+------------+-----------------+------+
| Scene_Id | Scene_Name | Scrn_ID | |
+----------+------------+-----------------+------+
| 1 | | Opening Scene | 1001 |
| 2 | | Climax Scene | 1001 |
| 3 | | End Credits | 1001 |
| 1 | | Opening Scene 1 | 1002 |
| 2 | | Character Intro | 1002 |
| 3 | | Conflict | 1002 |
| 4 | | Climax Scene | 1002 |
+----------+------------+-----------------+------+
Using an automatically generated primary key is actually the simplest solution:
scene_id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY
There is very little overhead in this.
It would be much more complicated and expensive to use numbers that are relative to scm_id – see the many questions for such a feature on this forum.
Keep it simple!

Which normal form or other formal rule does this database design choice violate?

The project I'm working on is an application that lets you design data entry forms, and automagically generates a schema in an underlying PostgreSQL database
to persist them as well as the browsing and editing UI.
The use case I've encountered this with is a store back-office database, but the app itself intends to be somewhat universal. The administrator creates the following entry forms with the given fields:
Customers
name (text box)
Items
name (text box)
stock (number field)
Order
customer (combo box selecting a customer)
order lines (a grid showing order lines)
OrderLine
item (combo box selecting an item)
count (number field)
When all this is done, the resulting database schema will be equivalent to this:
create table Customers(id serial primary key,
name varchar);
create table Items(id serial primary key,
name varchar,
stock integer);
create table Orders(id serial primary key);
create table OrderLines(id serial primary key,
count integer);
create table Links(id serial primary key,
fk1 integer references Customers.id,
fk2 integer references Items.id,
fk3 integer references Orders.id,
fk4 integer references OrderLines.id);
Links being a special table that stores all the relationships between entities; every row has (usually) two of the foreign keys set to a value, and the rest set to NULL. Whenever a new entry form is added to the application instance, a new foreign key referencing the table for this form is added to Links.
So, suppose our shop stocks some widgets, gizmos, and thingeys. A customer named Adam orders two widgets and three gizmos, and Betty orders four gizmos and five thingeys. The database will contain the following data:
Customers
/----+-------\
| ID | NAME |
| 1 | Adam |
| 2 | Betty |
\----+-------/
Items
/----+---------+-------\
| ID | NAME | STOCK |
| 1 | widget | 123 |
| 2 | gizmo | 456 |
| 3 | thingey | 789 |
\----+---------+-------/
Orders
/----\
| ID |
| 1 |
| 2 |
\----/
OrderLines
/----+-------\
| ID | COUNT |
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
\----+-------/
Links
/----+------+------+------+------\
| ID | FK1 | FK2 | FK3 | FK4 |
| 1 | 1 | NULL | 1 | NULL |
| 2 | 2 | NULL | 2 | NULL |
| 3 | NULL | NULL | 1 | 1 |
| 4 | NULL | NULL | 1 | 2 |
| 5 | NULL | NULL | 2 | 3 |
| 6 | NULL | NULL | 2 | 4 |
| 7 | NULL | 1 | NULL | 1 |
| 8 | NULL | 2 | NULL | 2 |
| 9 | NULL | 2 | NULL | 3 |
| 10 | NULL | 3 | NULL | 4 |
\----+------+------+------+------/
(The tables also contain a bunch of timestamps for auditing and soft deletion but I don't think they're relevant here, they just make writing the SQL by the administrator that much messier. The management app is also used to implement a bunch of different use cases, but they're generally primarily data entry, master-detail views, and either scalar fields or selection boxes.)
When I've had to write a join through this thing I'd grumbled about it to my coworker, who replied "well using separate tables for each relationship is one way to do it, this is another..." Leaving aside the obvious-to-me ugliness of the above and the practical issues, I also have a nagging feeling this has to be a violation of some normal form, but it's been a while since college and I'm struggling to figure out which of the criteria apply here.
Is there something stronger "well that's just your opinion" I can use when critiquing this design?

De-conflicting data strategies when associating two tables

I have some tables that look like this:
+------------+------------+------------+----------------+----------+
| Locations | HotelsA | HotelsB | HotelsB-People | People |
+------------+------------+------------+----------------+----------+
| LocationID | HotelAID | HotelBID | PersonID | PersonID |
| Address | HotelAName | HotelBName | HotelBID | Name |
| | LocationID | | | |
+------------+------------+------------+----------------+----------+
Currently, if I want to know what the address is of the hotel someone is staying at there is no way to make that association without manually looking through the names of HotelsA for something that looks similar enough to the name of HotelsB.
I would like to remove HotelBName and replace it with a foreign key to HotelAID (in this example it would actually make more sense to change HotelsB-People to HotelsAPeople, but there are additional columns that I have omitted for simplicity that prevent that solution from being viable in my particular case). The end result would look like this:
+------------+------------+-------------+----------------+----------+
| Locations | HotelsA | HotelsB | HotelsB-People | People |
+------------+------------+-------------+----------------+----------+
| LocationID | HotelAID | HotelBID | PersonID | PersonID |
| Address | HotelAName | FK_HotelAID | HotelBID | Name |
| | LocationID | | | |
+------------+------------+-------------+----------------+----------+
HotelAName and HotelBName are likely very similar, but inconsistently so. You could have "Springfield Marriott" in one and "Marriott, Springfield" in the other, but there's no consistency (no guarantee anything is spelled correctly either).
Are there any strategies for how this could be done as well as considerations for how to make the applications that utilize this data continue to work during the time it takes to fix all of the data?
Thank you.
I would just add the FK_HotelAID column to the HotelsB table. Assigning the correct id to that column will largely be a manual process, although you could try joining HotelAName to HotelBName to at least cover the ids for names that have a perfect match. Your applications should continue to work while you do this. After you've assigned all the ids inHotelsB you can define the foreign key and then delete the HotelBName column. Of course, any references that the applications make to HotelBName will need to be modified.

How do I construct this table relationship in SQL Server?

Sorry, if this a rather basic question but I'm a SQL Server noob in need of help.
I have 2 types of loan providers, Lender and Pingtree.
Both Lender and Pingtree can have a relationship with MatchService, which would need to be able to store their ID.
At the moment I'm struggling to work out how I can create a relationship between them. To demonstrate, I've created a simple visual of what I want to do in the real world (ringed in red) and what I think could be a possible solution in SQL Server. In essence Lender and Pingtree would have a ProviderId and this would be the ID also stored in the Match table
All advice appreciated.
If I were designing this table I would use a Provider to Match table, and store the common attributes in the Provider table. For the non-common attributes, I would create them as a name/value pair table that can link back to the provider Id.
edit: added sample of data structure.
MatchService (Key would be MatchId + ProviderId)
|MatchId |ProviderId|
---------------------------
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
Provider (Key would be ProviderId)
|ProviderId |ProviderType |ProviderName |StartDateTime | EndDateTime |
--------------------------------------------------------------------------
|1 |Lender |Stark Ind. |1/1/2013 00:00|1/1/2014 00:00|
|2 |Pingtree |MoneyBags |1/1/2013 00:00|1/1/2014 00:00|
Name/Value Pair Table (For Unique, Key would be ProviderId + Name)
| ProviderId | Name | Value |
-------------------------------------------------------
| 1 | PointOfContact | Tony Stark |
| 1 | Contact Phone Number | 101-202-3456 |
| 2 | Customer Service Number | 402-123-4567 |

How to store Goals (think RPG Quest) in SQL

Someone asked me today how they should store quest goals in a SQL database. In this context, think of an RPG. Goals could include some of the following:
Discover [Location]
Kill n [MOB Type]
Acquire n of [Object]
Achieve a [Skill] in [Skillset]
All the other things you get in RPGs
The best I could come up with is:
Quest 1-* QuestStep
QuestStep 1-* MobsToKill
QuestStep 1-* PlacesToFind
QuestStep 1-* ThingsToAcquire
QuestStep 1-* etc.
This seems a little clunky - Should they be storing a query of some description instead (or a formula or ???)
Any suggestions appreciated
User can embark on many quests.
One quest belongs to one user only (in this model).
One quest has many goals, one goal belongs to one quest only.
Each goal is one of possible goals.
A possible goal is an allowed combination of an action and an object of the action.
PossibleGoals table lists all allowed combinations of actions and objects.
Goals are ordered by StepNo within a quest.
Quantity defines how many objects should an action act upon, (kill 5 MOBs).
Object is a super-type for all possible objects.
Location, MOBType, and Skill are object sub-types, each with different properties (columns).
I would create something like this.
For the Quest table:
| ID | Title | FirstStep (Foreign key to GuestStep table) | etc.
The QuestStep table
| ID | Title | Goal (Foreign key to Goal table) | NextStep (ID of next QuestStep) | etc.
Ofcourse this is where the hard part start, how do we describe the goals? I'd say create one record for the goal in the Goal table and save each of the fields of the goal (I.E. how many mobs of what type to kill, what location to visit, etc.) in a GoalFields table, thus:
Goal table:
| ID | Type (type is one from an Enum of goal types) |
The GoalFields Table
| ID | Goal (Foreign key to goal) | Field | Value |
I understand that this can be a bit vague, so here is an example of what dat in the database could look like.
Quest table
| 0 | "Opening quest" | 0 | ...
| 1 | "Time for a Sword" | 2 | ...
QuestStep table
| 0 | "Go to the castle" | 0 | 1 | ...
| 1 | "Kill two fireflies" | 1 | NULL | ...
| 2 | "Get a sword" | 2 | NULL | ...
Goal table
| 0 | PlacesToFind |
| 1 | MobsToKill |
| 2 | ThingsToAcquire |
GoalFields table
| 0 | 0 | Place | "Castle" |
| 1 | 1 | Type | "firefly" |
| 2 | 1 | Amount | 2 |
| 3 | 2 | Type | "sword" |
| 4 | 2 | Amount | 1 |