473,398 Members | 2,812 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,398 software developers and data experts.

Finding the natural key

Whenever I want help on a query, I get told my design is wrong, So this
time I'm posting a message during the design phase: How am I going to
perfectly design the following?

We want to be able to track time for users for multiple modules, for
now a Schedule module and a Punchlist module. These modules already
exist and there are dozens of other modules which we will add to the
list as well, two or three at a time - so it should be possibly to add
to the list of related modules fairly easily.

In my mind the natural key is the UserOrContactId (an id for a
particular person), the date the time is for and ReferenceId to the
module it is in, either PunchlistItemId or ScheduleTaskId. I haven't
done the foreign keys yet and will do that once the table design is
settled. The MinutesSpent is going to be the minutes the person spent
doing a particular schedule task or punchlist item, which will be
converted from hours and minutes to just minutes for the database with
a constraint for total miuntes per day not being more than 24 hours.
Create and Update User/Time is a standard thing we put on all our
tables for auditing purposes. The ForDate will be the date the hours
happen so if the natural key is done right that will take care of
checking that two entries aren't made on the same day, i.e. the total
horus should just be updated if an entry exists.

The problem is that I can't make the natural key a primary key because
you can't have nulls in the primary key, i.e. it will be either a
PunchlistItem OR a Schedule Task, but not both for a particular record.
In the past I have done something like RefType = 'Schedule', RefId =
ScheduleTaskId, but then foreign keys can't be applied.

So what's the perfect solution so that I won't get heckled for design
when I ask a query question about it in a few months? Celko, get it all
out of your system - I don't understand database design, blah, blah,
blah, but show me the perfect solution.

CREATE TABLE [dbo].[TimeSpent](
[UserOrContactId] [int] NOT NULL,
[ForDate] [smalldatetime] NOT NULL,
[PunchlistItemId] [int] NULL,
[ScheduleTaskId] [int] NULL,
[MinutesSpent] [int] NOT NULL,
[Description] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL,
[Notes] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[CreateUser] [int] NOT NULL,
[CreateTime] [smalldatetime] NOT NULL,
[UpdateUser] [int] NOT NULL,
[UpdateTime] [smalldatetime] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
ALTER TABLE [dbo].[TimeSpent] WITH CHECK ADD CONSTRAINT [CK_RefIds]
CHECK (([PunchlistItemId] IS NOT NULL OR [ScheduleTaskId] IS NOT
NULL))
GO

Mar 15 '06 #1
13 3172
>> Whenever I want help on a query, I get told my design is wrong, So this
time I'm posting a message during the design phase: How am I going to
perfectly design the following?
First of all asking questions regarding a specific database design on a
public newsgroup is inherently a bad idea. Logical database design following
business/conceptual model and as such nobody in this newsgroup is familiar
with your business model other than you. Your problem may well be related to
the rest of the design and may affect other relevant subsystems/ modules/
infrastructure etc. And the advice which you receive here may be based on
what others perceive as the problem and may not be the actual design
problem, not to mention the chances of misunderstanding and
misinterpretation are very high.
We want to be able to track time for users for multiple modules, for now
a Schedule module and a Punchlist module. These modules already exist and
there are dozens of other modules which we will add to the list as well,
two or three at a time - so it should be possibly to add to the list of
related modules fairly easily.
Based on this narrative, one could conclude that a module is a well defined
entity and could come up with a table like:

CREATE TABLE Modules (
Module_id INT NOT NULL PRIMARY KEY,
Module_name VARCHAR(15) NOT NULL ) ;

INSERT Modules SELECT 1, 'Schedule' ;
INSERT Modules SELECT 1, 'Punchlist' ;
....
In my mind the natural key is the UserOrContactId (an id for a particular
person), the date the time is for and ReferenceId to the module it is in,
either PunchlistItemId or ScheduleTaskId. I haven't done the foreign keys
yet and will do that once the table design is settled. The MinutesSpent
is going to be the minutes the person spent doing a particular schedule
task or punchlist item, which will be converted from hours and minutes to
just minutes for the database with a constraint for total miuntes per day
not being more than 24 hours.


This does not make full sense, unless you can explain precisely each aspect
of the system within the limits of a newsgroup post.

Based on the narrative, if a person works in a module at a given time, you
can represent those facts in tables like:

CREATE TABLE Persons (
Person_id INT NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL,
... );

INSERT Persons SELECT 1, 'Joe' ;
INSERT Persons SELECT 2, 'Kim' ;
....

CREATE TABLE Activities (
Person_id NOT NULL
REFERENCES Persons ( Person_id )
ON UPDATE CASCADE
ON DELETE CASCADE,
Module_id NOT NULL
REFERENCES Modules ( Module_id )
ON UPDATE CASCADE
ON DELETE CASCADE,
Begin_date INT NOT NULL DEFAULT CURRENT TIMESTAMP,
End_date INT NOT NULL DEFAULT ('9999-12-31'),
...
PRIMARY KEY (Person_id, Module_id ) );

INSERT Activities SELECT 1, 1, '2006-01-01', '2006-01-03', ... ;
INSERT Activities SELECT 1, 2, '2006-02-01', '2006-02-15', ... ;
INSERT Activities SELECT 2, 1, '2006-01-02', '2006-01-14', ... ;
INSERT Activities SELECT 2, 2, '2006-01-28', '2006-02-20', ... ;

Having distinct temporal attributes for each module, allows you to infer the
time spent on each module by a person. If multiple people can work on the
same module, consider adding the Begin_Date column to the key. In that case,
if this table is being referenced by many other tables, it might be a good
idea to consider a surrogate.

Like I said, unless a thorough analysis of the business model is done, most
of the effort will be wasted over nonsensical arguments over silly issues
like what is "natural" and what is not. If you find this time critical and
the task is overwhelming, perhaps considering a professional hire might
help.

--
Anith
Mar 15 '06 #2
What Anith said. Have a modules table. Much happier in the long run.
Aniht has a typo in the insert statement - they can't both have the
same id. I'm sure it is a typo.

Also,why description AND notes? Is description from a pick list? if
so, have a descriptions table.

Anohter module could be "Vacation", and pretty soon you have a standard
time tracking system.

Mar 15 '06 #3
A user is going to do some work on a particular day and then they are
going to record the fact that they spent 30 minutes, 2 hours or
whatever on a *particular schedule task* and want to report on it
later. Are you saying I should turn the 30 minutes into a date range?
The user won't specify that information - they will just know that on
Tuesday they spent an hour working on schedule task 1 on Monday and two
hours working on schedule task 2 on Tuesday.

I do like the Modules table idea, I am going to play with the table
design a bit and see how that works - Thanks. But I need to use some
combination of the Module and the line item in the module as part of
the key to uniqueness.

Mar 15 '06 #4
Oh yeah.. And why are your dates created as integers?

I'll probably take out the description column, but sometimes people
want a short description of something but they also want to type a
novel to describe it.. Having one short and one long text fields lets
them do that.

Mar 15 '06 #5
I played with adding a Module table but then I lose ref integrity when
the module line items are deleted. So I would need to add a
ModuleLineItem table as well (??) and then I have ref integrity
problems with the other tables linking to it...

P.S. Identity columns are awesome.

Mar 15 '06 #6
pb648174 (go****@webpaul.net) writes:
A user is going to do some work on a particular day and then they are
going to record the fact that they spent 30 minutes, 2 hours or
whatever on a *particular schedule task* and want to report on it
later. Are you saying I should turn the 30 minutes into a date range?
The user won't specify that information - they will just know that on
Tuesday they spent an hour working on schedule task 1 on Monday and two
hours working on schedule task 2 on Tuesday.
Given that information, it seems reasonable to just have a counter,
suggestively in minutes. (Disclaimer: I did not read your original post
very closely.)

....however, it reminds me of our old time-reporting system we had my
office for several years, a hack developed by a colleague over a
Christmas holiday. Here you could enter start and stop for activities.
You didn't have to, and the only thing that mattered was was the hours
worked. But it was very user-friendly, since I didn't have to count
hours in my head, I could just write down how my day had been, easily
rearranging some hours if I wanted to save some typing.
Oh yeah.. And why are your dates created as integers?


I suspect that was a type of Anith. Maybe he had hours or minutes
originally and then changed his mind.

In any case, there is a flaw with his date formats, remove the hyphens:
99991231 etc, to make sure that the dates are always interpreted the
same.
--
Erland Sommarskog, SQL Server MVP, es****@sommarskog.se

Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pro...ads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodinf...ons/books.mspx
Mar 15 '06 #7
That is a good idea, I think I might include that feature, but also
allow minutes/hours to be entered. In that case, should I have just a
start and end date and just make one up if they enter minutes, or just
have the minutes as null if they start/stop and vice versa? I think I
lean towards the second option so later I'll be able to tell if they
did start/stop or manually entered their time.

Mar 16 '06 #8
Ok, so here is the final solution as I have it now, sans the start/stop
stuff and references to other tables:

CREATE TABLE [dbo].[TimeSpentItem](
[Id] [int] IDENTITY(1,1) NOT NULL,
[PunchlistItemId] [int] NULL,
[ScheduleTaskId] [int] NULL,
CONSTRAINT [PK_TimeSpentItem] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[TimeSpentItem] WITH CHECK ADD CONSTRAINT
[CK_TimeSpentItem_ValidReference] CHECK (([PunchlistItemId] IS NOT
NULL OR [ScheduleTaskId] IS NOT NULL))
GO

CREATE TABLE [dbo].[TimeSpentActual](
[UserOrContactId] [int] NOT NULL,
[ForDate] [smalldatetime] NOT NULL,
[TimeSpentItemId] [int] NOT NULL,
[Minutes] [int] NOT NULL,
[Notes] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[CreateUser] [int] NOT NULL,
[CreateTime] [smalldatetime] NOT NULL,
[UpdateUser] [int] NOT NULL,
[UpdateTime] [smalldatetime] NOT NULL,
CONSTRAINT [PK_TimeSpentActual_1] PRIMARY KEY CLUSTERED
(
[UserOrContactId] ASC,
[ForDate] ASC,
[TimeSpentItemId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
ALTER TABLE [dbo].[TimeSpentActual] WITH CHECK ADD CONSTRAINT
[FK_TimeSpentActual_TimeSpentItemId] FOREIGN KEY([TimeSpentItemId])
REFERENCES [dbo].[TimeSpentItem] ([Id])
GO
ALTER TABLE [dbo].[TimeSpentActual] WITH CHECK ADD CONSTRAINT
[CK_TimeSpentActual_ValidForDate] CHECK ((datepart(hour,[ForDate])=(0)
AND datepart(minute,[ForDate])=(0) AND datepart(second,[ForDate])=(0)))
GO
ALTER TABLE [dbo].[TimeSpentActual] WITH CHECK ADD CONSTRAINT
[CK_TimeSpentActual_ValidTime] CHECK ((isnull([Minutes],(0))<(1439)))

Mar 16 '06 #9
>played with adding a Module table but then I lose ref integrity when
the module line items are deleted. So I would need to add a

so, don't let them be deleted. Trust me on this one, you REALLY want to
have a modules table.

Mar 16 '06 #10
>A user is going to do some work on a particular day and then they are
going to record the fact that they spent 30 minutes, 2 hours or
whatever on a *particular schedule task* and want to report on it

so, back to the subject line. The "natural key" is description, notes,
date, and module.

or, the identity key and display the rest of the junk.

BTDT.

Mar 16 '06 #11
>> Oh yeah.. And why are your dates created as integers?

It is supposed to be a temporal datatype like DATETIME or SMALLDATETIME
depending on your needs.

--
Anith
Mar 16 '06 #12
pb648174 (go****@webpaul.net) writes:
Ok, so here is the final solution as I have it now, sans the start/stop
stuff and references to other tables:

CREATE TABLE [dbo].[TimeSpentItem](
[Id] [int] IDENTITY(1,1) NOT NULL,
[PunchlistItemId] [int] NULL,
[ScheduleTaskId] [int] NULL,
CONSTRAINT [PK_TimeSpentItem] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[TimeSpentItem] WITH CHECK ADD CONSTRAINT
[CK_TimeSpentItem_ValidReference] CHECK (([PunchlistItemId] IS NOT
NULL OR [ScheduleTaskId] IS NOT NULL))
Can both be non-NULL? What does that mean? That you are working
on both in parallel?

Should there not be UNIQUE constraint on the two?

Having re-reread your original post a little better, I agree entirely
with anyone else tha you need a Modules table. You will have to change
that TimeSpentItem table for each new module that is added.
CREATE TABLE [dbo].[TimeSpentActual](
[UserOrContactId] [int] NOT NULL,
[ForDate] [smalldatetime] NOT NULL,
[TimeSpentItemId] [int] NOT NULL,
[Minutes] [int] NOT NULL,
[Notes] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,


The users really need the ability to write novels? Would not a
varchar(8000) do? Text is fairly messy to deal with.
--
Erland Sommarskog, SQL Server MVP, es****@sommarskog.se

Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pro...ads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodinf...ons/books.mspx
Mar 16 '06 #13
You mean something different than TimeSpentItem or is TimeSpentItem
sufficient? I usually use varchar, but this time I'm experimenting with
not just to see how much of a hassle it is. No matter what we make the
text limit, someone, somewhere ends up complaining about it.

Mar 18 '06 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Sean Ross | last post by:
Hi. Recently I made a small script to do some file transferring (among other things). I wanted to monitor the progress of the file transfer, so I needed to know the size of the files I was...
0
by: C. Barnes | last post by:
Summary: Sorts strings in a way that seems natural to humans. If the strings contain integers, then the integers are ordered numerically. For example, sorts into the order . Code:
1
by: Connelly Barnes | last post by:
Summary: Sorts strings in a way that seems natural to humans. If the strings contain integers, then the integers are ordered numerically. For example, sorts into the order . Code: ...
15
by: Twan Kennis | last post by:
Hi, I have a DB2 database on the IBM iSeries platform, on which I created several Stored Procedures with the SQLCODE as a return-parameter. These Stored Procedures are called from a Windows...
4
by: sathyashrayan | last post by:
(This is not a home work question) Dear group, I want a program to find one number between a set of natural number.A program to guess a number in between a Natural number set.This should be a...
1
by: Hendri Adriaens | last post by:
Hi, I have an onmouseover script that displays a div with some comment. There are several links getting this onmouseover functionality, all with their own comment text. Now I want the div to...
1
by: Steven Bird | last post by:
NLTK — the Natural Language Toolkit — is a suite of open source Python modules, data sets and tutorials supporting research and development in natural language processing. It comes with 50k lines...
7
by: joproulx | last post by:
Hi, I was wondering if there was a way with Reflection to find dynamically if an object was referencing indirectly another object. A simple example would be: Object1 | --Object2 |
275
by: Astley Le Jasper | last post by:
Sorry for the numpty question ... How do you find the reference name of an object? So if i have this bob = modulename.objectname() how do i find that the name is 'bob'
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.