Wondering if someone could assist with the best way to handle storing "checked" items in a MSSQL database.
On my form, i have a list of fields (name, address ect) and then a listbox the user can check for e.g. favourite colors.
In my database I would have a table for user details (tbl_userdetails - [UserID, Address...]) and a table for colors (tbl_colors, [ColorID, ColorName, ColorCode]). I would also need a table for user colors (tbl_userColors - [userID, ColorID])Theses would be linked via a "userID"
Normally, to save the user details, I have a sql string "UPDATE tbl_userdetails SET... WHERE userID = #userID". What is the best way to save the changed checked items into the next table?
My thoughts are:
Delete all the colors for UserID in the tbl_userColors and then loop the checked items into a "INSERT" statment.
Loop though each item that exists in the list create a datatable and then "merge" the data (on match, insert. on not matched delete)
Any other thoughts? What is the best way to build the INSERT statment?
Cheers
The DELETE and INSERT strategy works well as long as nothing is tied to those records. If you ever have any tables that reference tbl_userColors on the "one" side of the relationship, then you will have headaches.
The MERGE strategy is decent, usually. One possibly unfortunate consequence would be that a MISSING record is the same as a FALSE record. For instance, you Have your list of colors, {red, green, blue}, and your users are making their selections. Six months later you get crazy and add orange. Now you have no idea who didn't select orange vs. those that simply weren't presented with orange as an option.
A third option is to place an Enabled BIT field on the tbl_userColors table. This allows you to determine if a user was presented with a color option and they declined it vs. if the user never saw a particular color option.
Speaking of Enabled BITs. Your tbl_colors table should really have an Enabled BIT as well - or some other mechanism of removing a color from the UI without removing its database record. You realize at some point you no longer want to offer blue to your users, but you also don't want to loose the historical data.
And a small aside: Your tables names are horrific. You should really consider dropping the Hungarian notation. I'm a big fan of camel-case table names: Users, Colors, and UserColors.
Simple really. When an item is checked it returns a boolean. Whenever you get ready to save to the database you just want to loop through the colors and if it is checked (AKA is check is true) then you add it to a list that you can later loop through to save all of the values.
Related
I am setting up a database for our hunting club, plus learning access along the way...ouch
I want the database to contain all of the deer observed along with their locations, when the user enters the data it will go as buck/doe/fawn/unknown and they will also enter the location where the deer was observed. The location could be a stand located at various different places on the property or a stand could be located on a food plot.
Here is where I am confused, I got to this point and really just don't know the best path to follow. I have followed much of the normalization techniques and set up relationships. I am working with a form (frmEnterNewStand) to add the stands to the database, what I need is a single combo box with choices that come from two tables (tblProperty Sections for stands not located on food plots) and (tblFoodplots for stands located on food plots). But couldn't figure that one out. So I attempted to add food plots as another entry but things started getting messy.
Since I am new to this I don't even know the right questions to ask, but I just cannot figure out the best way to organize this to be able to enter data easily then access the data easily.
I know we will want to perform queries to get statistics on, i.e. how many deer were observed blah blah blah, we will also want to query the food plots as well, how many deer were seen on food plot 1 for example, and what time of day. We will also keep up with other food plot parameters.
I have been taking the Udemy course and have several books, but my mind is blown, any help would be appreciated.
I am going to include an example map of our property, the blue numbers are different sections for the property (tblPropertySections), the yellow S numbers are Stand 1, 2 etc, the orange F numbers are Food Plot 1, 2 etc.
Also included are my current screenshots of what I have so far. I was going to try to post images but I need at least 10 reputation points i guess.
NOt sure what else I need to provide but I will say thank you in advance
tim
thank you
tim
I think you should start simple on this and add complexity as needed.
From my reading of the problem the main outcome is a database that records deer sightings. The easiest possible "database" is just a table that lists the sighting, and associated info.
For example:
ID, Date, Time, DeerType, Location, SeenBy, Comments
1, 1/1/2015, 11:45pm, "Doe", "Behind the shed", "Garry Abblet", "After a few beers Garry went for a slash and saw a deer"
Start with that and then worry about what needs to be added. I know a single table isn't the most exciting database to learn about, but you should follow a philosophy of the simplest solution usually being the best.
Access forms are essentially the visual representation of tables. In fact, if users were just computers you would not need a user interface but can manage processing (edit, add, save, delete) through code. The combo box form control is the tool needed to select corresponding data from other tables, specifically foreign keys.
As you point out, a Stand can either be on a Property Section or Food Plot. So in the tblStands table you can carry two foreign keys: Property Section ID and Food Plot ID.
Then, on their corresponding forms of tblStands the IDs wold be stored/bounded in combo boxes whose RowSources are a queries of the underlying tables:
SELECT id, PropertySectionName FROM tblPropertySections
SELECT id, FoodPlotName FROM tblFoodPlots
Now, computers would know which ID to pick but not humans who would need names/titles to help identify which item to select. Fortunately, combo boxes come with a special hidden column feature where the IDs can be hidden from view but its related name is presented on the form. However, the ID is stored in table. You set this up with the wizard when you select and position combo boxes.
Manually, or no-wizard approach, you do the following in Property Sheet of selected combo box:
Format tab
Column Count: 2 (or any greater than 2 depending on RowSource query)
Column Width: 0"; 1" (or any non-zero that fits into combo box's width)
Data tab
Control Source: PropertySheetID (or FoodPlotID)
Row Source: (see above queries)
Row Source type: table/query
Bound column: 1
Altogether, users will navigate to frmEnterNewStand and choose if the Stand is on Property Section or Food Plot by entering one combo box and not the other (leave label instructions as needed, since users are human).
Suppose I have Item and Tag, each of which have an id and name column only, and an Item_Tag_Map table that has a composite Item.id, Tag.id primary key.
If I want to implement a history table for Item and Tag, this seems relatively straightforward - I can add a third column revision and a trigger to copy into an ItemHistory or TagHistory table with id, revision as primary key and operation ("INSERT","UPDATE",etc). Since I may want to "delete" items, I can go about this one of two ways:
Add another column on Item or Tag for is_active, and do not actually delete any rows ever
Delete rows, but record the deletion in the history table as a delete operation, and on an Item or Tag insert, make sure to get the latest revision number from the ItemHistory or TagHistory table with that item, and set it to be that
The second option leaves a bad taste in my mouth, so I am fine with using the first. After all, why should I really ever need to delete an item when I can just modify it or change its active status?
Now, I've run into the same problem for the history table on the Item_Tag_Map table, but this time, neither option seems all that attractive. If I choose to add an is_active for the Item_Tag_Map, the logic of finding out whether a tag is mapped to an item changes from:
Get ALL tag_mapping for THESE items
to
Get ALL tag_mapping for THESE items WHERE is_active
The implicit idea that the presence of a mapping means that the mapping exists goes away. The set of unmapped item-tags not only includes all the ones that are not present in the table, but also the ones where is_active is false.
On the other hand, if I choose the second option, it's still rather ugly.
I'm sure people have run into this problem many times before, and I am interested in learning how you have dealt with it.
My answer depends on a few things, so I'll try to state my assumptions.
No matter what I think is_active on Item and Tag are ok. If the record size grows very fast on those two entities, then consider running a nightly job to move the inactive records to an archived version of the tables. This can be used for reporting or auditing of things later. You can also write a script to restore records if you need, but the idea is that your real time tables are fast and without deleted data.
If you allow the user to add/update/delete mappings, then I would consider the table the same as Item and Tag. Add the flag and use it in your queries. It doesn't seem ugly to me - I've seen it before.
If the mapping table isn't under user control, then I would guess you would use the is_active flag on either Item or Tag to determine whether or not a query could be run.
Just know that once you add that flag, people will forget to use it. I know I've done it many times, ("Why did I get so many records, what am I missing? Oh yeah, is_active...)
Working with cascading choices in the new(er) FMP seems to be a little weird. My intention is to create a bunch of drop-down lists / pop ups that rely on the previous choice. If a user clicks on a Customer drop-down, the next drop-down (address field) will ONLY have related data for that customer street address. Once you click the certain address, the other state, city, zip, etc fields will be automatically keyed in.
This is done by creating two tables (shipping, customer) along with a table occurrence of shipping and one unique value as a relationship in both the customer and shipping table...yeah. All of this is very doable, if not a little convoluted; however, I was wondering if there was a way to clean up these relationships? Sorry, calling all FileMaker pros out there, thanks!
I'm afraid the answer is no. Setting up cascaded value lists is rather tedious and, to my knowledge, there's no silver bullet. You're lucky to have just two levels :)
If I were going to take a stab at this, I'd try to build the next level of popup contents by deriving the necessary value list from the records of a related table. Since the selection of one value triggers the next popup, you're finding entries in a predefined database made of multiple tables where the values are all the possible dropdown list/popups. It's a cascade engineered through layouts, find and sort.
I'm creating a database with Access. This is just a test database, similar to my requirements, so I can get my skills up before creating one for work. I've created a database for a fictional school as this is a good playground and rich data (many students have many subjects have many teachers, etc).
Question 1
What is the difference, if any, between using a Lookup column and a many-to-many associate table?
Example: I have Tables 'Teacher' and 'Subject'. Many teachers have many subjects. I can, and have, created a table 'Teacher_Subject' and run queries with this.
I have then created a lookup column in teachers table with data from subjects. The lookup column seems to take the place of the teacher_subject table. (though the data on relationships is obviously duplicated between lookup table and teacher_subject and may vary). Which one is the 'better' option? Is there a snag with using lookup tables?
(I realize that this is a very 'general' question. Links to other resources and answers saying 'that depends...' are appreciated)
Question 2
What attracts me to lookup tables is the following: When creating a form for entering subjects for teachers, with lookup I can simply create checkboxes and click a subject for a teacher 'on' or 'off'. Each click on/off creates/removes a record in the lookup column (which replaces teacher_subject).
If I use a form from a query from teacher subject with teacher as main form and subject as subform I run into this problem: In the subform I can either select each subject that teacher has in a bombo box, i.e. click, scroll down, select, go to next row, click, scroll down, etc. (takes too long) OR I can create a list box listing all available subjects in each row but allowing me to select only one. (takes up too much space). Is it possible to have a click on/off list box for teacher_subject, creating/removing a record there with each click?
Note - I know zero SQL or VB. If the correct answer is "you need to know SQL for this" then that's cool. I just need to know.
Thanks!
Lookup columns in tables will cause you more stress than joy. Unless you need them for Sharepoint, they should be avoided. You may wish to read http://r937.com/relational.html and http://www.mvps.org/access/tencommandments.htm
I wouldn't use them. Your example is fine, but there are limitations. What do you do when you need to reference another field from the Subject table other than the name? How would you differentiate subjects that are only offered on a semester basis?
You have no way of getting a count of how many subjects each teacher is assigned without some ugly coding.
Another limitation, is when you start identifying who taught what courses during a given school year.
I'm kind of unclear on your second question, but it sounds to me like you need a subform with a dropdown list.
If you want to do the checkbox thing, it quickly becomes a lot more complicated. To me, you're starting from user interface and working backwards to structure, instead of going the other direction.
I hesitate to mention it, but in terms of full disclosure you should know that in A2007 and A2010, you have multi-value fields available, and they are presented with exactly the UI you describe. But they have many of the same problems as lookup fields, and are quite complex to work with in code. Behind the scenes, they are implemented with a standard many-to-many join table, but it's all hidden from you.
I wish MS would make the listbox with checkbox control that is used with MV fields available for all listboxes, but binding that to a many-to-many join table would be complex if the listbox control were not designed for that (with link child/link master properties, for instance).
I tried to come up with a way to offer you the UI feature you prefer from multi-value fields without actually using multi-value fields. That seems challenging to me.
The closest I could come up with is to load a disconnected recordset with your "List" choices and a check box field. Then create a form, or subform, based on that recordset which you present in datasheet view. It could look similar to a combo bound to a multi-value field. In the after update event of the checkbox field, you would need code to add or remove a record from the junction table as required.
However, I don't know if this is something you would care to tackle. Earlier you indicated a willingness to learn SQL if needed; the approach I'm suggesting would also require VBA. Maybe take a look at Danny Lesandrini's article, Create In-Memory ADO Recordsets, to see whether it is something you could use.
OTOH, maybe the most appropriate answer for you is to keep the multi-value fields and get on with the rest of your life. I'm stuck. But now that we know you are actually using multi-value fields, perhaps someone else will be able to offer you a more appropriate suggestion.
I have an application with multiple "pick list" entities, such as used to populate choices of dropdown selection boxes. These entities need to be stored in the database. How do one persist these entities in the database?
Should I create a new table for each pick list? Is there a better solution?
In the past I've created a table that has the Name of the list and the acceptable values, then queried it to display the list. I also include a underlying value, so you can return a display value for the list, and a bound value that may be much uglier (a small int for normalized data, for instance)
CREATE TABLE PickList(
ListName varchar(15),
Value varchar(15),
Display varchar(15),
Primary Key (ListName, Display)
)
You could also add a sortOrder field if you want to manually define the order to display them in.
It depends on various things:
if they are immutable and non relational (think "names of US States") an argument could be made that they should not be in the database at all: after all they are simply formatting of something simpler (like the two character code assigned). This has the added advantage that you don't need a round trip to the db to fetch something that never changes in order to populate the combo box.
You can then use an Enum in code and a constraint in the DB. In case of localized display, so you need a different formatting for each culture, then you can use XML files or other resources to store the literals.
if they are relational (think "states - capitals") I am not very convinced either way... but lately I've been using XML files, database constraints and javascript to populate. It works quite well and it's easy on the DB.
if they are not read-only but rarely change (i.e. typically cannot be changed by the end user but only by some editor or daily batch), then I would still consider the opportunity of not storing them in the DB... it would depend on the particular case.
in other cases, storing in the DB is the way (think of the tags of StackOverflow... they are "lookup" but can also be changed by the end user) -- possibly with some caching if needed. It requires some careful locking, but it would work well enough.
Well, you could do something like this:
PickListContent
IdList IdPick Text
1 1 Apples
1 2 Oranges
1 3 Pears
2 1 Dogs
2 2 Cats
and optionally..
PickList
Id Description
1 Fruit
2 Pets
I've found that creating individual tables is the best idea.
I've been down the road of trying to create one master table of all pick lists and then filtering out based on type. While it works, it has invariably created headaches down the line. For example you may find that something you presumed to be a simple pick list is not so simple and requires an extra field, do you now split this data into an additional table or extend you master list?
From a database perspective, having individual tables makes it much easier to manage your relational integrity and it makes it easier to interpret the data in the database when you're not using the application
We have followed the pattern of a new table for each pick list. For example:
Table FRUIT has columns ID, NAME, and DESCRIPTION.
Values might include:
15000, Apple, Red fruit
15001, Banana, yellow and yummy
...
If you have a need to reference FRUIT in another table, you would call the column FRUIT_ID and reference the ID value of the row in the FRUIT table.
Create one table for lists and one table for list_options.
# Put in the name of the list
insert into lists (id, name) values (1, "Country in North America");
# Put in the values of the list
insert into list_options (id, list_id, value_text) values
(1, 1, "Canada"),
(2, 1, "United States of America"),
(3, 1, "Mexico");
To answer the second question first: yes, I would create a separate table for each pick list in most cases. Especially if they are for completely different types of values (e.g. states and cities). The general table format I use is as follows:
id - identity or UUID field (I actually call the field xxx_id where xxx is the name of the table).
name - display name of the item
display_order - small int of order to display. Default this value to something greater than 1
If you want you could add a separate 'value' field but I just usually use the id field as the select box value.
I generally use a select that orders first by display order, then by name, so you can order something alphabetically while still adding your own exceptions. For example, let's say you have a list of countries that you want in alpha order but have the US first and Canada second you could say "SELECT id, name FROM theTable ORDER BY display_order, name" and set the display_order value for the US as 1, Canada as 2 and all other countries as 9.
You can get fancier, such as having an 'active' flag so you can activate or deactivate options, or setting a 'x_type' field so you can group options, description column for use in tooltips, etc. But the basic table works well for most circumstances.
Two tables. If you try to cram everything into one table then you break normalization (if you care about that). Here are examples:
LIST
---------------
LIST_ID (PK)
NAME
DESCR
LIST_OPTION
----------------------------
LIST_OPTION_ID (PK)
LIST_ID (FK)
OPTION_NAME
OPTION_VALUE
MANUAL_SORT
The list table simply describes a pick list. The list_ option table describes each option in a given list. So your queries will always start with knowing which pick list you'd like to populate (either by name or ID) which you join to the list_ option table to pull all the options. The manual_sort column is there just in case you want to enforce a particular order other than by name or value. (BTW, whenever I try to post the words "list" and "option" connected with an underscore, the preview window goes a little wacky. That's why I put a space there.)
The query would look something like:
select
b.option_name,
b.option_value
from
list a,
list_option b
where
a.name="States"
and
a.list_id = b.list_id
order by
b.manual_sort asc
You'll also want to create an index on list.name if you think you'll ever use it in a where clause. The pk and fk columns will typically automatically be indexed.
And please don't create a new table for each pick list unless you're putting in "relationally relevant" data that will be used elsewhere by the app. You'd be circumventing exactly the relational functionality that a database provides. You'd be better off statically defining pick lists as constants somewhere in a base class or a properties file (your choice on how to model the name-value pair).
Depending on your needs, you can just have an options table that has a list identifier and a list value as the primary key.
select optionDesc from Options where 'MyList' = optionList
You can then extend it with an order column, etc. If you have an ID field, that is how you can reference your answers back... of if it is often changing, you can just copy the answer value to the answer table.
If you don't mind using strings for the actual values, you can simply give each list a different list_id in value and populate a single table with :
item_id: int
list_id: int
text: varchar(50)
Seems easiest unless you need multiple things per list item
We actually created entities to handle simple pick lists. We created a Lookup table, that holds all the available pick lists, and a LookupValue table that contains all the name/value records for the Lookup.
Works great for us when we need it to be simple.
I've done this in two different ways:
1) unique tables per list
2) a master table for the list, with views to give specific ones
I tend to prefer the initial option as it makes updating lists easier (at least in my opinion).
Try turning the question around. Why do you need to pull it from the database? Isn't the data part of your model but you really want to persist it in the database? You could use an OR mapper like linq2sql or nhibernate (assuming you're in the .net world) or depending on the data you could store it manually in a table each - there are situations where it would make good sense to put it all in the same table but do consider this only if you feel it makes really good sense. Normally putting different data in different tables makes it a lot easier to (later) understand what is going on.
There are several approaches here.
1) Create one table per pick list. Each of the tables would have the ID and Name columns; the value that was picked by the user would be stored based on the ID of the item that was selected.
2) Create a single table with all pick lists. Columns: ID; list ID (or list type); Name. When you need to populate a list, do a query "select all items where list ID = ...". Advantage of this approach: really easy to add pick lists; disadvantage: a little more difficult to write group-by style queries (for example, give me the number of records that picked value X".
I personally prefer option 1, it seems "cleaner" to me.
You can use either a separate table for each (my preferred), or a common picklist table that has a type column you can use to filter on from your application. I'm not sure that one has a great benefit over the other generally speaking.
If you have more than 25 or so, organizationally it might be easier to use the single table solution so you don't have several picklist tables cluttering up your database.
Performance might be a hair better using separate tables for each if your lists are very long, but this is probably negligible provided your indexes and such are set up properly.
I like using separate tables so that if something changes in a picklist - it needs and additional attribute for instance - you can change just that picklist table with little effect on the rest of your schema. In the single table solution, you will either have to denormalize your picklist data, pull that picklist out into a separate table, etc. Constraints are also easier to enforce in the separate table solution.
This has served us well:
SQL> desc aux_values;
Name Type
----------------------------------------- ------------
VARIABLE_ID VARCHAR2(20)
VALUE_SEQ NUMBER
DESCRIPTION VARCHAR2(80)
INTEGER_VALUE NUMBER
CHAR_VALUE VARCHAR2(40)
FLOAT_VALUE FLOAT(126)
ACTIVE_FLAG VARCHAR2(1)
The "Variable ID" indicates the kind of data, like "Customer Status" or "Defect Code" or whatever you need. Then you have several entries, each one with the appropriate data type column filled in. So for a status, you'd have several entries with the "CHAR_VALUE" filled in.