I am looking for help with database design for a small project I am working on.
In short what I am trying to achieve is to have say the following tables:
Paddocks
Paddock ID
Paddock Name
Paddock Size
etc.
Cattle
Herd ID
Herd Name
Number of cows
Current Paddock
Cattle_Movements
Herd Name
Current Paddock
New Paddock
Date
etc.
I was hoping to have the 'Cattle_Movements' table be like a summary of all movements of a herd of cattle. And when a herd is moved from one paddock to another it would update the 'Current Paddock' field in the 'Cattle' table.
At this stage I am trying to workout the relationships, queries and high level process that I will need to implement.
Any help will be greatly appreciated.
Start by setting up a normalized table structure. make the tables below and hook them together with the relationships tool on the ribbon under database tools-relationships. To create a relationship drag the primary key from one table to the corresponding and same named foreign key in the table that will be the many side of the relationship. In the pop up make sure to check the enforce referential integrity, cascade update, and cascade delete checkboxes.
I've highlighted the two "Many to Many Relationships" in this normalization. HerdsPaddocks is a more generic name for the CattleMovements Table. There are other possible normalized table structures, but the subtle differences are beyond the scope of this answer. When you are ready, look up table normalization and Many to Many Relationships.
Next, Close the Relationships tool, select a table from the sidebar and on the ribbon under Create hit create form. Do this for all the tables. Now we have a working database but you need to learn how to use it. So play!
Below I gave some play suggestions, but just play with everything until you figure out how to use the forms to (add, search, edit) cows, herds, and paddocks. Also learn why you should delete the primary keys from all the forms and how to replace the foreign keys like CattleType in the Cattle Table with the user friendly CattleTypeDesscription from the CattleTypes Table.
Start with the Herds table and enter some random herds. (pro tip: never add data to the table directly except when playing the error rate is too high). Then Open the herds form where you can browse and edit the herds.
Play tips: In the Table Herds HerdID is both an autonumber and a primary key. It behaves differently from the other columns. Check it out. after that delete the HerdID textbox from the form and see what happens(a good thing). How do you add herds using the Herds Form?
Moving on to playing with the Cattle form, first make sure to add a few CattleTypes to the CattleTypes table. Then at some point, try replacing the CattleTypeID in the Cattle Form with the CattleTypeDescription: https://btabdevelopment.com/how-to-change-a-text-box-to-a-combo-box-wont-work-with-data-access-page/
Also, note the Cattle Form has a subform allowing you to simultaneously assign/edit cattle assignments to herds.
Once you are comfortable adding and editing data, play with the query editor. For instance, to get how many cows are currently in Paddock holds10cattle (my dummy data).
query 1 showing the relevant data
results from query1:
Query 2 getting really close:
Query 3: which gives the number 2:
'Query 3 SQL from SQL pane of query designer
SELECT Count(Cattle.CowName) AS CountOfCowName
FROM Paddocks INNER JOIN ((Herds INNER JOIN (Cattle INNER JOIN CattleHerds ON Cattle.CattleID = CattleHerds.CattleID) ON Herds.HerdID = CattleHerds.HerdID) INNER JOIN HerdsPaddocks ON Herds.HerdID = HerdsPaddocks.HerdID) ON Paddocks.PaddockID = HerdsPaddocks.PaddockID
GROUP BY Herds.HerdName, Paddocks.PaddockName, HerdsPaddocks.HerdPaddockEndDate, HerdsPaddocks.HerdPaddockStartDate
HAVING (((Paddocks.PaddockName)="holds10cattle") AND ((HerdsPaddocks.HerdPaddockEndDate) Is Null) AND ((HerdsPaddocks.HerdPaddockStartDate)<Now()))
ORDER BY HerdsPaddocks.HerdPaddockStartDate;
Next Steps could include the specific paddock with a parameter and using the query in a report.
Related
I am currently working in a SQL server database where I have a table User that has a schema like so:
username
category
user1
gaming
user2
gaming
user3
sports
My summary table UserCategoryCount is a simple groupby statement for how many users belong to each category and looks like this:
category
numUsers
gaming
2
sports
1
New entries are constantly being uploaded to the User, and I want to be able to stream updates in the User table to the UserCategoryCount summary table. I am aware that I can create a simple VIEW statement that performs a groupby on the User table, but I would like UserCategoryCount to be its own table that automatically changes based on new users being uploaded to the User table.
My first thought was to create a trigger that will detect when the User table has been updated. So far, the most simple but cheesy solution I can think of is creating a trigger that simply deletes and refreshes UserCategoryCount:
CREATE TRIGGER TRG_Add_User
ON User
AS
BEGIN
DELETE FROM UserCategoryCount
INSERT INTO UserCategoryCount (category, numUsers)
SELECT Category, Count(Category) as numUsers
FROM User GROUP BY Category
END
GO
But this seems like a really hacky way of updating the UserCategoryCount table. Any help on how to improve this update statement so that I don't have to completely overwrite the table every time a new user or batch of users has been inserted would be greatly appreciated.
For a start, your trigger is seriously flawed: it does not use the inserted or deleted tables and instead recalculates the whole thing every time, this is going to be very bad for performance. It also does not specify whether it is for inserts, updates or deletes.
A much better solution is to use an indexed view. This is like a regular view, except that the server maintains the actual data on disk, and updates it in real-time whenever there are changes to the underlying tables.
CREATE OR ALTER VIEW dbo.UserCategoryCount
WITH SCHEMABINDING
AS
SELECT
u.Category,
COUNT_BIG(*) AS numUsers
FROM dbo.User u
GROUP BY u.Category;
GO
CREATE UNIQUE CLUSTERED INDEX CX_UserCategoryCount ON dbo.UserCategoryCount (Category);
There are some restrictions on indexed views, among them:
They must be schema-bound, and therefore underlying columns cannot be changed
All tables must be two-part, schema and table
Only joins allowed are INNER or CROSS, no LEFT/RIGHT/FULL/APPLY or derived tables, CTEs or subqueries.
If there is a GROUP BY, you must add COUNT_BIG, and the only other aggregate allowed is SUM
I'm creating a rather large APEX application which allows managers to go in and record statistics for associates in the company. Currently we have a database in oracle with data from AD which hold all the associates information. Name, Manager, Employee ID, etc.
Now I'm responsible for creating and modeling a table that will house all their stats for each employee. The table I have created has over 90+ columns in it. Some contain data such as:
Documents Processed
Calls Received
Amount of Doc 1 Processed
Amount of Doc 2 Processed
and the list goes on for well over 90 attributes. So here is my question:
When creating this table in my application with so many different columns how would I go about choosing a primary key that's appropriate? Should I link it to our employee table using the employees identification which is unique (each have a associate number)?
Secondly, how can I create these tables (and possibly form) to allow me to associate the statistic I am entering for an individual to the actual individual?
I have ordered two books from amazon on data modeling since I am new to APEX and DBA design. Not a fresh chicken, but new enough to need some guidance. An additional problem I am running into is that each form can have only 60 fields to it. So I had thought about creating tables for different functions out of my 90+ I have.
Thanks
4.2 allows for 200 items per page.
oracle apex component limits
A couple of questions come to mind:
Are you sure that the employee Ids are not recyclable? If these ids are unique and not recycled.. you've found yourself a good primary key.
What do you plan on doing when you decide to add a new metric? Seems like you might have to add a new column to your rather large and likely not normalized table.
I'd recommend a vertical table for your metrics.. you can use oracle's pivot function to make your data appear more like a horizontal table.
If you went this route you would store your employee Id in one column, your metric key in another, and value...
I'd recommend that you create a metric table consisting of a primary key, a metric label, an active indicator, creation timestamp, creation user id, modified timestamp, modified user id.
This metric table will allow you to add new metrics, change the name of the metric, deactivate a metric, and determine who changed what and when.
This would be a much more flexible approach in my opinion. You may also want to think about audit logs.
I am trying to implement a system on my website similar to that of Facebook's "Like" feature. Where users can click a button which counter++'s. However, I have run into a problem in terms of efficiently storing data into my DB.
Each story has it's own row in the stories table in my DB with the columns like and users_like.
I want each person to only be able to like the story once. Therefore I need to somehow store data that shows that the user has, in fact, like++'d the post.
All I could thing of was to have a column named users_like and then add each user, followed by a comma, to the column using CONCAT and then using the php function to explode the data.
However, this method, as far as I know, is in the opposite direction of database normalization.
What is the best way to do this and I understand "best" is subjective.
I cannot add a liked flag to the user table because there will be a vast number of stories the person could 'like.'
Thanks
You need a many to many table in your database that will store a foreign key to the stories table and a foreign key to the user table. You put a constraint on this table saying that the story fk - user fk combo must be unique.
You now don't even have to have a like column, you just count the number of rows in the many to many table corresponding to your story.
I have a database that stores some users in it. Each user has its account settings, privacy settings and lots of other properties to set. The number of those properties started to grow and I could end up with 30 properties or so.
Till now, I used to keep it in "UserInfo" table having User and UserInfo related as One-To-Many (keeping a log of all changes). Putting it in a single "UserInfo" table doesn't sound nice and, at least in the database model, it would look messy. What's the solution?
Separating privacy settings, account settings and other "groups" of settings in separate tables and have 1-1 relations between UserInfo and each group of settings table is one solution, but would that be too slow (or much slower) when retrieving the data? I guess all data would not be presented on a single page at the same moment. So maybe having one-to-many relationships to each table is a solution too (keeping log of each group separately)?
If it's only 30 properties, I'd recommend just creating 30 columns. That's not too much for a modern database to handle.
But I would guess that if you ahve 30 properties today, you will continue to invent new properties as time goes on, and the number of columns will keep growing. Restructuring your table to add columns every day may become time-consuming as you get lots of rows.
For an alternative solution check out this blog for a nifty solution for storing lots of dynamic attributes in a "schemaless" way: How FriendFeed Uses MySQL.
Basically, collect all the properties into some format and store it in a single TEXT column. The format is semi-structured, that is your application can separate the properties if needed but you can also add more at any time, or even have different properties per row. XML or YAML or JSON are example formats, or some object serialization format supported by your application code language.
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
user_proerties TEXT
);
This makes it hard to search for a given value in a given property. So in addition to the TEXT column, create an auxiliary table for each property you want to be searchable, with two columns: values of the given property, and a foreign key back to the main table where that particular value is found. Now you have can index the column so lookups are quick.
CREATE TABLE UserBirthdate (
user_id BIGINT UNSIGNED PRIMARY KEY,
birthdate DATE NOT NULL,
FOREIGN KEY (user_id) REFERENCES Users(user_id),
KEY (birthdate)
);
SELECT u.* FROM Users AS u INNER JOIN UserBirthdate b USING (user_id)
WHERE b.birthdate = '2001-01-01';
This means as you insert or update a row in Users, you also need to insert or update into each of your auxiliary tables, to keep it in sync with your data. This could grow into a complex chore as you add more auxiliary tables.
I have a SQL Server as backend and use ms access as frontend.
I have two tables (persons and managers), manager is derived from persons (a 1:1 relation), thus i created a view managersFull which is basically a:
SELECT *
FROM `managers` `m`
INNER JOIN `persons` `p`
ON `m`.`id` = `p`.`id`
id in persons is autoincrementing and the primary key, id in managers is the primary key and a foreign key, referencing persons.id
now i want to be able to insert a new dataset with a form in ms access, but i can’t get it to work. no error message, no status line, nothing. the new rows aren’t inserted, and i have to press escape to cancel my changes to get back to design view in ms access.
i’m talking about a managers form and i want to be able to enter manager AND person information at the same time in a single form
my question is now: is it possible what i want to do here? if not, is there a “simple” workaround using after insert triggers or some lines of vba code?
thanks in advance
The problem is that your view is across several tables. If you access multiple tables you could update or insert in only one of them.
Please also check the MSDN for more detailed information on restrictions and on proper strategies for view updates
Assuming ODBC, some things to consider:
make sure you have a timestamp field in the person table, and that it is returned in your managers view. You also probably need the real PK of the person table in the manager view (I'm assuming your view takes the FK used for the self-join and aliases it as the ID field -- I wouldn't do that myself, as it is confusing. Instead, I'd use the real foreign key name in the managers view, and let the PK stand on its own with its real name).
try the Jet/ACE-specific DISTINCTROW predicate in your recordsource. With Jet/ACE back ends, this often makes it possible to insert into both tables when it's otherwise impossible. I don't know for certain if Jet will be smart enough to tell SQL Server to do the right thing, though.
if neither of those things works, change your form to use a recordsource based on your person table, and use a combo box based on the managers view as the control with which you edit the record to relate the person to a manager.
Ilya Kochetov pointed out that you can only update one table, but the work-around would be to apply the updates to the fields on one table and then the other. This solution assumes that the only access you have to these two tables is through this view and that you are not allowed to create a stored procedure to take care of this.
To model and maintain two related tables in access you don’t use a query or view that is a join of both tables. What you do is use a main form, and drop in a sub-form that is based on the child table. If the link master and child setting in the sub-form is set correctly, then you not need to write any code and access will insert the person’s id in the link field.
So, don’t use a joined table here. Simply use a form + sub-form setup and you be able to edit and maintain the data and the data in the related child table.
This means you base the form on the table, and not a view. And you base the sub-form on the child table. So, don't use a view here.