Database design to hold a person's information that changes with time? - sql

We use a third-party product to manage our sports centre membership. We have several membership types (eg. junior, student, staff, community) and several membership statuses (eg. annual, active, inactive, suspended). Unfortunately the product only records a member's current membership type and status. I'd like to be able to track the way our members' type and status have changed over time.
At present, we have access to the product's database design. It runs on SQL Server and we regularly run our own SQL queries against the product's tables to produce our own tables. We then link our tables to pivot-tables in Excel to produce charts. So we're familiar with database design and SQL. However we're stuck as to how to best approach this problem.
The product records a member's membership purchases and their start and expiry dates. So we can work back through that data to determine a member's type and status at any point in time. For example, if they bought a junior membership on Jan 1, 2007 and it expired on Dec 31, 2007 and then they bought a student membership on Jun 1, 2008, we can see their status went from active to inactive to active (on Jan 1, 2008 and Jun 1, 2008, respectively) and their type went from junior to student (on Jun 1, 2008).
Essentially we'd like to turn a member's type and status properties into temporal properties or effectivities a-la Fowler (or some other thing that varies with time).
Our question (finally :) - given the above: what database table design would you recommend we use to hold this member information. I imagine it would have a column for MemberID so we can key into the existing Member table. It would also need to store a member's status and type and the date range they were held for. We'd like to be able to easily write queries against this table(s) to determine how many members of each type and status we had at a given point in time.
UPDATE 2009-08-25: Have been side-tracked and haven't had a chance to try out the proposed solutions yet. Hope to do so soon and will select an answer based on the results.

Given that your system is already written and in place, the simplest approach to this problem (and the one that affects the existing database/code the least), is to add a membership history table that contains MemberID, status, type and date columns. Then add an UPDATE and an INSERT trigger to the main member table. When these triggers fire, you write the new values for the member (along with the date of the status change) into the member history table. You can then just query this table to get the histories for each member.
This is fairly simple to implement, and won't affect the existing system at all.
I'll write this for you for a free membership. :)

I cannot recommend you enough to read Joe Celko's "Sql for smarties - advanced sql programming". he has a whole chapter on temporal database design AND how to (effeciently and effectively) run Temporal Projection, Selection and Temporal Join queries. And I would not do him justice to even attempt to explain what he says in his chapter in this post.

I would create a reporting database that was organized into a star schema. The membership dimension would be arranged temporally, so that there would be different rows for the same member at different points in time. That way different rows in the fact table could pertain to different points in history.
Then I would create update procedures for updating the reporting database periodically, say one a week, from the main database. This is where the main work would come.
Then, I would drive the reports off the reporting database. It's pretty easy to make a star schema do the same things a pivot table does. If necessary, I'd get some kind of OLAP tool to sit in front of the reporting database.
This is a lot of work, but it would pay off over time.

I would put the membership info in it's own table with start and end dates. Keeping the customer in separate table. This is a pain if you need the "current" membership info all the time but there are many ways to get around that either through queries or triggers.

Related

Search one table (Encounters Table) for all records - Insert Totals into a Providers Table

Search one table (Encounters Table) for all records - Insert Totals into a Providers Table
Encounters table lists every hospital encounter over time. Each Encounter record has a Provider (Provider is also in the Providers Table one time as a record - 229 providers, presently.)
The encounter table lists the date and the provider, so that one provider may have 15 to 20 encounter records for that date.
In the Providers table I have been trying to get a count in different fields (formula fields) that will list the number of encounters for the provider in a time frame. Examples of the time frame are current week, past week... or could be last month, two months ago, etc. So the Providers Table primarily would have a key field of Providers which would relate to the Providers in the Encounter table.
Now the software used is Quickbase which is a Cloud Based Database used by the hospital I work for.
I have been unable to use a one-to-many relationship to pull the Provider from the Encounters table into the Provider's table. The column generated is blank. So when I try to pull encounter counts into formula number fields like 'current_week', last_week, last_month, etc. the counts just say 0.
The Quickbase help tells me that I need to populate the related Provider fields so the names appear, but I'm thinking I can't just use a file import (ie CSV file) to fill in the Encounters table since it has thousands of records and there are only 229 providers.
Queries can be done, and knowing that SQL handles this type of work, it just seems that may be the best way to handle this. My SQL isn't that good, but I think I could write a formula that handles this with two tables. I just am not certain how to fill the Encounter Count fields.
This is a bit of a hurdle and perhaps because I'm using a proprietary software package 'Quickbase' it may not be possible.
I do know that queries are used in Quickbase, so the logic of a SQL statement should work in the dialog box used to write formulas in QB.
Any help would be appreciated.
If the only place you need the see the # of Encounters Per Provider in a time frame, I'd try to make it work with a Summary Field in Quickbase and apply a filter for a date range (I'm assuming there is an existing relationship between Providers and Encounters where Providers is the parent).
You can get some good tips on how to configure that field in the Quickbase Community https://community.quickbase.com/home

SQL - MS Access Form design - add data of ISA relationships

I'm taking a DBMS course and I need to design and build my own DB. I have a database for a hospital where doctors,nurses,support staff etc are in a ISA relationship to an Employee entity with the rest of the data like the name, address , salary and the rest of the employee data.
Designing a form, I want to be able to add an employee with all of their data in one form.
Is there a way to do a "conditional table" of sorts where if i select "doctor" from a drop-down i get to add to the doctor table too, and same for the rest of the entities under the ISA relationship?
Thx!
As a general rule, when dealing with data, you do NOT flip or switch tables for a given form or relatonal database design.
So, for example. If I have a table of customers. Well, now if I want to mark some of the customers as plumbers, and others as doctors? I don't create two tables.
All I would do is add ONE column to that customers table and it would simply allow me to set the type of customer. The reason for this design is "many" but some significant reasons are:
For each new type of customer, you would not create a new table. Worse, all of the forms, the reports, the SQL, the code you write? Well, all of that code would have to be modified EACH time you create a new table. So, you SIMPLY cannot adopt a design in which the concept of changing a table is part of that process.
Forms are bound to ONE table. For related data, you in most cases will use a sub form.
So, think of even a accounting system. They can have huge numbers of customers, and as a result, you can "query" that table to give you all customers. Or you might ask how many accounting firms are in the customer list. Or make a report that summeries by customer type a "count" of each type of customer.
So, buidling forms, or reports? They cannot on the fly "change" the tables they are using.
So, in place of a tables called:
SalesJan
SalesFeb
SalesMar
etc.
Well, now you can't query sales from Jan to mar, because the data is in different tables.
So, what you do is have ONE table called "sales", and you add ONE column of the date. Now, at the start of each new month, you don't have to create a new table.
Now, of course in some cases it makes sense to create a separate table. For example, a table of customers, and a table of employees in a database is just fine. It makes sense in this case to use two tables, since the information about a customer and what they can do and the kind of information is VERY different then how you would deal with employees.
So, with above? Well, if I need to print mailing labels for all customers and all employees? That would require two different reports. And very likely the table structure for the two tables is different.
Bottom line:
If you working on design or form or report? And you needing to try and change the table that the form/report/code etc is going to operate on? This is a sign that your design approach has gone complete off the rails and is the wrong design.
So, in the case of doctors, nurses etc.? Well, they are all hospital staff, and MOST of the basic information about such employees will be common, much the same, and thus a SINGLE table of "employees" makes the most sense. You would only need a nice "employee type" combo box on that one form, and thus you can add/enter/edit/search any employee in that one table.
The fact that you "want to search" for a employee show that all these people "are" employees and thus belong in one table. And the basic information about all employees is going to be the same anyway. If you find you are attempting to create a new table but with near identical structures over and over, then just like a new table for each month sales, or a new table for each new kind of employee? Simply add the "one" column that allows you to make that distinguish, and not a whole new table.
Now one COULD even attempt to put patients in the same table, but then again, dealing with patents as opposed employees is a considerable different kind of "thing".
So employees are employees - even different kinds. (manager, cleaning staff etc.).
And patients are patients - even different kinds (long term care, emergency etc.).

Opinions on planning and avoiding data redundancy

I am currently going to be designing an app in vb.net to work with an access back-end database. I have been trying to think of ways to reduce down data redundancy
and I have an example scenario below:
Lets imagine, for an example purpose, I have a customers table and need to highlight all customers in WI and send them a letter. The customers table would
contain all the customers and properties associated with customers (Name, Address, Etc) so we would query for where the state is "WI" in the table. Then we would
take the results of that data, and append it into a table with a "completion" indicator (So from 'CUSTOMERS' to say 'WI_LETTERS' table).
Lets assume some processing needs to be done so when its completed, mark a field in that table as 'complete', then allow the letters to be printed with
a mail merge. (SELECT FROM 'WI_LETTERS' WHERE INDICATOR = COMPLETE).
That item is now completed and done. But lets say, that every odd year (2013) we also send a notice to everyone in the table with a state of "WI". We now query the
customers table when the year is odd and the customer's state is "WI". Then append that data into a table called 'notices' with a completion indicator
and it is marked complete.
This seems to keep the data "task-based" as the data is based solely around the task at hand. However, isn't this considered redundant data? This setup means there
can be one transaction type to many accounts (even multiple times to the same account year after year), but shouldn't it be one account to many transactions?
How is the design of this made better?
You certainly don't want to start creating new tables for each individual task you perform. You may want to create several different tables for different types of tasks if the information you need to track (and hence the columns in those tables) will be quite different between the different types of tasks, but those tables should be used for all tasks of that particular type. You can maintain a field in those tables to identify the individual task to which each record applies (e.g., [campaign_id] for Marketing campaign mailouts, or [mail_batch_id], or similar).
You definitely don't want to start creating new tables like [WI_letters] that are segregated by State (or any client attribute). You already have the customers' State in the [Customers] table so the only customer-related attribute you need in your [Letters] table is the [CustomerID]. If you frequently want to see a list of Letters for Customers in Wisconsin then you can always create a saved Query (often called a View in other database systems) named [WI_Letters] that looks like
SELECT * FROM Letters INNER JOIN Customers ON Customers.CustomerID=Letters.CustomerID
WHERE Customers.State="WI"

Creating Table Relationships

I am working on a VB.net (VS-2010, Win XP Pro 2 SP3), Employee Management Project. I need to keep track of Employee Leave Attendance and also each Equipment assigned to an Employee. How can I achieve this using SQLlite.
It will be very useful if you could provide me with examples as I am completely new to the field of SQL and VB.net
I think this can be done with two tables where one has the primary key while the other has a foreign key, but I am not sure. Also how many tables will I need for storing data in Leave and Equipment Form.
I went through other questions but I was unable to figure out a solution for my problem.
(Sorry, I cannot provide with images as this site prevents me from posting images without 10 reps)
Most problems are only as complex, and as simple as you make them. Out of habbit, nearly all tables end up with a unique ID field. There are exceptions, which I will call "link" tables, eg, ones that provide connection details between two data tables.
Now, in your senario
You would need a "holiday" table, where each row will contain the employee unique ID and either a start/finish date, eg, if they take half a day, it needs to be visible, or, just a year and value, eg in 2011, I booked, 2 lots of 35 hours, and 1 lot of 4 hours eg, Ive taken 2 weeks and half a day.
For the equipment, you would need a data table, since an item can only got to 1 employee, it depends if you're going to use this for booking or not, but if its just like a library, eg I currently have a loaner laptop, then you can just have an employee field in the equipment table. If you need a booking system, then you would require link tables and more complex.
Best way to work out your tables is to try and group your data, and then write the items on peices of paper and see how you as a human do it. After a while you end up able to do so in your head.

Help me with my SQL project (please)

For this grading period, my CS teacher left us a open-choice project involving SQL and Delphi/VB.
I ended up with the assignment of designing and building a program that allowed the users to, through a GUI in Delphi/VB, insert and read hurricane data pulled from a database (latest SQL Server, by the way). However, there are a few catches.
Three tables are required: Hurricanes, Hurricane_History, and Category
The Category table is not meant to be modified, and it contains the columns 'Min. Speed', 'Max. Speed', and 'Category'. The idea is that a hurricane with a rotational speed of X falls into category Y if X is within the minimum and maximum speed of category Y.
The Hurricane table is meant to be modified by the end-user, through the Delphi/VB gui. It contains the following columns: 'Name', 'Day', 'Time', 'Rotational_Speed', 'Movement_Speed', 'Latitude', 'Longitude', and 'Photo'.
Then there is the Hurricane_History table, which contains 'Name', 'Category', 'Starting_DateTime', 'Ending_DateTime', 'Starting Latitude', 'Starting Longitude', 'Ending Latitude', 'Ending Longitude'. This table is not meant to be directly modified, but rather automatically populated through SQL (I figure using SQL triggers and stored procedures).
What the program should end up doing is the following: The user opens the visual app, and enters in information for a certain hurricane. Since only the table Hurricanes is meant to be modified, the user would insert the Name, Day, Time, Current Rotational Speed, Current Movement speed, current latitude, current longitude, and, optionally, a picture.
If the user enters a hurricane that does not exist yet, then it would create a new hurricane with the corresponding data in the Hurricane_History table. If he enters data for a hurricane that already exists, then the data for that hurricane should be updated, and stored into the corresponding Hurricane_History row. Furthermore, the current category of the hurricane should be automatically populated with SQL using the data that was stored in the Category table.
So far, I have the three tables, the columns, the Delphi GUI, the connections (between Delphi and SQL Server), etc.
What I'm having a real hard time with is the SQL Triggers and Stored procedures needed to generate the data in the Hurricane_History table. Here's my algorithm, the first one for populating the category, and the second one for populating the data of the Hurricane_History table:
create trigger determine_category on Hurricanes for insert, update as
*when a value is inserted into Hurricanes.Rotational_Speed, match it with the corresponding row in the Categories table, and insert the corresponding category into the Category column of the hurricane's Hurricane_History row.*
create trigger populate_data on Hurricanes for insert, update as
*if Hurricane.name exists, perform an update instead of an insert for using Hurricanes.Day as Hurricanes_History.Ending_Day, Hurricanes.Latitude and Hurricane.Longitude as Hurricanes_History.Ending_Latitude and Hurricanes_History.Ending_Longitude, and the Category using the determine_category trigger.*
*if Hurricane.name does not exist, create a record in Hurricanes_History using the data from the newly inserted Hurricane record, and populating the Category using the determine_category trigger*
What I need help with is translating my thoughts and ideas into SQL code, so I was wondering if anyone might want to help me throughout this.
Thanks a bunch!
EDIT:
I just whipped up a simple stored procedure for determining the category. What I don't know how to do is use the result/output of the stored procedure as an insertion value. Does anyone have insight on how to do it?
CREATE PROCEDURE determine_category
#speed int(5)
AS
SELECT Category FROM Categories
WHERE Max_Speed >= #speed AND Min_Speed >= #speed
First, since you're using SQL Server and you can use stored procedures, don't use a trigger. It's not necessary. If your teacher needs justification, here's an article from SQL Server MVP Tom LaRock which discusses issues with handling triggers.
Second, as far as how to write the stored procedures, think about how to handle all the functionality logically. You've said you need to do the following:
Read existing hurricane information
Update existing hurricane information
Insert a new hurricane into the database
Your application should handle all of those as separate paths. And you need to think about the functionality before you write your first bit of T-SQL code. That means you have to have an interface which presents existing information. You're going to have to display the hurricanes existing in the database. Then once the user selects the one to get more information on, you'll have to pull back the hurricane history information. So I know in that situation I have two different data retrievals based on user input. That tells me I need to build the GUI interface to handle that progression logically and display the information in a way the user can use. And it also tells me I've got to build two different stored procedures. The second one will be passed some information identifying the hurricane to retrieve data on (which would be the primary key).
Now roll through the rest of the application's functionality. That should get you started.
Rather than use triggers to do this, I would be more inclined to perform logical DML SQL statements inside transactions. Triggers, whilst sometimes proving useful, are not really necessary in this scenario (unless they are required for your coursework).
As a first approach, think about what is required to complete the application -
A UI layer to present data to the user, allow a user to search, insert, update (and possibly delete) hurricane data.
In this layer, we'll most likely want to
1.present users with a list of previous hurricanes, perhaps with some key details displayed and give users the ability to select a particular hurricane and see all the details.
2.give users the ability to insert new hurricane data. Think about how category will be displayed to a user to choose and how inputted data will be taken from this layer and ultimately end up in the data layer. Think also about how and if we should validate the user input. What needs to be validated? Well, ensuring against SQL injection, that values are in permitted ranges and lengths, etc. if this were a real application, then user input validation would be a necessity.
A data layer used to store the data in a defined entity relationship.
A data access layer used to perform all data access logic in regard to manipulating the application data.
A Business logic layer that contains the classes required for the application. Will contain any of the rules associated with the entities and will be used to present data to the UI layer.
We could take an extremely simplified approach and have the UI layer call straight into the data layer through stored procedures (which would be acting as our data access layer and also our business logic layer as they will encapsulate the rules regarding whether a hurricane record already exists and needs updating or a new record needs creating, possibly some validation too).
Re: Inserting sproc output into a table. Use the following general syntax:
INSERT INTO table (field1, field2, field3)
EXEC yourSproc(param, param)
In the insert documentation, search for execute_statement for details.