Summary:
I have a table that has a uique primary key identifying each record. I also have three more fields that can identify a record:
Category
CategoryNumber
DuplicateNumber
When I add a new record and choose the Category, how can I get CategoryNumber to increment correctly based on whether it is a duplicate or not.
Note that this is one big table. This is merely an upgrade from excel to access.
tldr:
Yesterday I asked about how to deal with multiple keys in Access. May be I did not ask the right question because my problem is even more puzzling today.
Here is what I am trying to do and where I am getting stuck.
I am creating a database to keep track of my film photos taken on a variety of different films and formats with different cameras (a total of 18 different independent pieces of information for each photo) that span back almost 15 years. Years ago I kept the data in MS Excel and programed the input form to do what I am about to explain.
I wanted to keep track of the photos in two ways. The first was a master photo number that would let me know how many total photos I had in my files. It was a sequentail number that I never intended to ever delete something in that sequence. It would be a number that would uniquely identify each photo. I see this as my primary key for the whole database.
But I also wanted to file the slides, negatives, and transparencies according to general groups or categories so that I could quickly pull them if I needed to make a photo submission or I was looking for something specific. So I also added a category identifer (e.g. Landscapes had a 'LS' name attached as well or Sunsets as 'SS' etc). I also wanted to keep a running sequential number for each slide that was in each category. So e.g. one of my first photos in my data base has PhotoID = 3, its Category = LS and its CategoryID = 1. Further down I have PhotoID = 14, Category = LS and CategoryID = 2.
Now in addition to these, I further have another number that I need to keep track of and that was if I made duplicate exposures of the same scene. To work this I just added a DuplicateNumber to each photo. If it had no duplicates then DuplicatNumber was 0, if it had one dupe than DuplicateNumber was 1, 2 dupes, DuplicateNumber was 2 etc.
So I had two ways for finding any photo in my files. Either by the PhotoID which was sequential in the Database but not in my physical files, or by the combination of Category, CategoryID and DuplicateNumber, which are how I physically file the photos.
Now in Excel what I did was when I opened my form, I first had to choose what category to put the photo in via radio buttons on the form. I would then fill in all the pertinent data for the photo. When I executed the form, it would find the last number in the master sheet, increment it and add all the data to a new record. It would then activate the category sheet for the category I chose, determine the last number in that sheet, increment it and add in the new data there as well.
An important note is that DuplicateNumber is always 0 by defalut unless I made it 1, 2 etc. It was never computed, but I entered it.
When I created slide lables (the "report") I would include the main PhotoID, The CategoryName, CategoryID and DuplicateNumber in this format (1LS1.0, 14LS45.0, 15LS45.1) and in addtion the location and Date taken.
But now I don't want to use Excel anymore and have tried to migrate the database to MS Access. So I have one main table called PhotoDetails.
PhotoID is the primary key in this table. It has a PhotoCategory field that is a number that has a relation to another table called Category. Its Primary key is PhotoCategoryID and it is also a foreign key in PhotoDetails. PhotoCategoryID is a number that identifies each category. In the list of all my categories, LS is number 11. But here is where I get stuck.
I have CategoryNumber, which is the number identifying the photo in each category, and DuplicateNumber, identifying the number of duplicates, in the PhotoDetal table. What I can't figure out is when I add a new photo, how do I increment the CategoryNumber? The form I have right now allows me to enter in all the data, and when I click to enter the next it will autonubmer the PhotoID key, but what about CategoryNumber? I can't remember what the last number is for each Category so as for me to enter that number in myself. Unless I mimic what I did in Excel by having all the data stored twice, once in the PhotoDetails (aka Master Sheet in Excel) and again in multiple Category tables. I was hoping Access could provide me a workaround.
Currently the relationships I have are the Category table linked to PhotoDetails in a 1-M relation. I also have several other tables all linked in a 1-M relation (e.g. table Film stores the different films I have used and the 1-M relation lets me link what film to each slide, and most of the other data is stored in that way).
I have 31 different Categories. Each photo has a Category and a CategoryID number, as well as a Duplicate number. I will choose the Category on data entry and the DuplicateNumber, but I want the CategoryID number as well as PhotoID to be incremented automatically for me. What is the correct way to proceed with this where I only have to keep one PhotoDetail table that is not duplicated for each category as I did in Excel.
OK, so basically what you are looking to do is "normalize" your data
Typically you would have two tables
Photo
PhotoID (Data Type: Autonumber - not normally seen by the user - Primary Key)
PhotoRefID (DT: probably a Number or Text - referencing the physical number)
CategoryID (DT: Number - a Long Integer - key to the Category table)
Duplicate (DT: Number - probably long also - if this is just a count)
-- or --
DuplicateOf (DT: Number - Long Integer - to reference what it is a duplicate of)
Category
CategoryID (DT: AutoNumber - Primary Key)
Description (DT: Text)
You will use relationships (Tools->Relationships) to like the two Category IDs together.
You can then be able to use the tables to build the forms and queries that you are looking for.
Note: If you can have photos that fit into more than one category, then you will need a third intermediate table to join them up. Something like:
PhotoCategories
PhotoCategoryID (DT: Autonumber, Primary Key)
PhotoID (DT: Number Long Integer)
CategoryID (DT: Number Long Integer)
I'd look at doing it cheaply by adding code so that when you try to add a new record it does a search in the database for the highest number with the category/duplicate/etc and then you can increment it in code before you add the new record.
There's no easy way to get this functionality automatically in Access, unless you break your table out into more tables.
-Adam
Related
I have been working on a database design and I'm stuck hitting a wall. I'm ending up with what I'm reading is not a normalized database structure but I'm having issues trying to find a "more correct" design and if this design is acceptable how do I execute it in Access?
TLDR: If a table with a single column set as an auto number is an acceptable design, how do you go about inserting a record in it using Access?
The segment of the database of concern is creating a structure for storing companies. Requirements for this is that any changes need to be approved by another user and all historical changes need to be captured so that it can be easily reverted also a company can have multiple aliases but only one legal name.
There is three tables in my solution but one of them is a single column table. From what I've read 95% of people on stack overflow all think its a very bad idea but I've found one post were people are that there are cases for it. I think this is not normal also because I can't find a way to just create a new record in a table with only an auto number column (In Access I have not tried others yet).
Table Structure
Company Names : ID, Company ID, Is Legal Name, Created By, Created On, Approved On, Approved By, Event ID, Is Active
(A company could have a few different names known to the public: TD vs Toronto Dominion. Each name is inserted here with a reference to the company it belongs to)
Companies : ID (Auto Number)
(A company exists and this is its ID)
Companies History : ID, Company ID, Market ID, Holding Company ID, Created By, Created On, Approved On, Approved By, Event ID, Is Active
(These are the historical changes that have been made to the company and who did them and who approved them)
Column Notes:
Event ID : is a FK reference to a table holding each record of actions that have either created, updated or deleted records. (User Research using method [y], Typo Fix, ...)
Is Active : Since deleting records is not possible (historical records need to be kept) this column is used to track if this record is to be included in queries.
Options I see and their issues:
I could get rid of the companies table and make Companies History : ID be the new company id but I find that in that case each time I want to update a company I would need to update each FK reference to the previous company id (I don't think this would be a very normalized approach)
Another Option I see is that I get rid of Companies table and use Company Names : ID as the company id and I would add a column to Company Names called Alias of Company ID. I find that solution adds a log of complexity to my stored data where an alias has company information that differs from the entry that was aliased.
Another Option is that I could add the columns: Created By, Created On, Approved On, Approved By, Event ID and Is Active but this would be duplicating information found in the first record for this company in the Companies History table and this isn't adding any real description to this record.
Anther Option is that I make the Companies table a mirror of Companies History and that when I update or insert a record in Companies I would also insert a record Companies History. With this solution I find that again I duplicate information, that newest record in "Companies History" would hold the same information found in last Inserted or Updated record in in Companies
Another option but is to replace the Companies : ID auto number with a short text and I just get the hash of the current timestamp + a random int. I can now insert new records into this table using access but I feel that this is overkill since I just need the exact same functionality as the auto number.
Another option is move only the legal name into Companies table but now when the legal name of a company changes I have no way of tracking this. Also if I want a list of all names I need to use a union on Companies and Company Names. I find that using unions can reduce performances of queries and I use them only when explicitly needed.
If I don't want to duplicate any information and I don't want to update all FK it seems that I need a table with a single column. If this is acceptable how do I go about inserting a record into a table with a single column set to auto number in Access.
If Companies can be derived from CompanyNames (select distinct CompanyId from CompanyNames), there is no point storing again that information. Just replace that table by a view if you want it (but it as little added value).
On the other hand, if CreatedOn refers to the Company creation (not the row creation) then it is obviously a property of the Company, and I would rather work with
Companies --> Aliases.
But of course I don't know the ins and outs of the reality you're dealing with.
I hope someone can help me with this:
I have a simple query combining a list of names and basic details with another table containing more specific information. Some names will necessarily appear more than once and arbitrary distinctions like "John Smith 1" and "John Smith 2" are not an option, so I have been using an autonumber to keep the records distinct.
The problem is that my query is creating two records for each name that appears more than once. For example, there are two clients named 'Sophoan', each with a different id number, and the query has picked up each one twice resulting in four records (in total there are 122 records when there should only be 102). 'Unique values' is set to 'yes'.
I've researched as much as I can and am completely stuck. I've tried to tinker with sql but it always comes back with errors, I presume because there are too many fields in the query.
What am I missing? Or is a query the wrong approach and I need to find another way to combine my tables?
Project in detail: I'm building a database for a charity which has two main activities: social work and training. The database is to record their client information and the results of their interactions with clients (issues they asked for help with, results of training workshops etc.). Some clients will cross over between activities which the organisation wants to track, hence all registered clients go into one list and individual tables spin of that to collect data for each specific activity the client takes part in. This query is supposed to be my solution for combining these tables for data entry by the user.
At present I have the following tables:
AllList (master list of client names and basic contact info; 'Social Work Register' and 'Participant Register' join to this table by
'Name')
Social Work Register (list of social work clients with full details
of each case)
Social Work Follow-up Table (used when staff call social work clients
to see how their issue is progressing; the register has too many
columns to hold this as well; joined to Register by 'Client Name')
Participants Register (list of clients for training and details of
which workshops they were attended and why they were absent if they
missed a session)
Individual workshop tables x14 (each workshop includes a test and
these tables records the clients answers and their score for each
individual test; there will be more than 20 of these when the
database is finished; all joined to the 'Participants Register' by
'Participant Name')
Queries:
Participant Overview Query (links the attendance data from the 'Register' with the grading data from each Workshop to present a read-only
overview; this one seems to work perfectly)
Social Work Query (non-functional; intended to link the 'Client
Register' to the 'AllList' for data entry so that when a new client
is registered it creates a new record in both tables, with the
records matched together)
Participant Query (not yet attempted; as above, intended to link the
'Participant Register' to the 'AllList' for data entry)
BUT I realised that queries can't be used for data entry, so this approach seems to be a dead end. I have had some success with using subforms for data entry but I'm not sure if it's the best way.
So, what I'm basically hoping to achieve is a way to input the same data to two tables simultaneously (for new records) and have the resulting records matched together (for new entries to existing records). But it needs to be possible for the same name to appear more than once as a unique record (e.g. three individuals named John Smith).
[N.B. There are more tables that store secondary information but aren't relevant to the issue as they are not and will not be linked to any other tables.]
I realised that queries can't be used for data entry
Actually, non-complex queries are usually editable as long as the table whose data you want to edit remains 'at the core' of the query. Access applies a number of factors to determine if a query is editable or not.
Most of the time, it's fairly easy to figure out why a query has become non-editable.
Ask yourself the question: if I edit that data, how will Access ensure that exactly that data will be updated, without ambiguity?
If your tables have defined primary keys and these are part of your query, and if there are no grouping, calculated fields (fields that use some function to change or test the value of that field), or complex joins, then the query should remain editable.
You can read more about that here:
How to troubleshoot errors that may occur when you update data in Access queries and in Access forms
Dealing with Non-Updateable Microsoft Access Queries and the Use of Temporary Tables.
So, what I'm basically hoping to achieve is a way to input the same data to two tables simultaneously (for new records) and have the resulting records matched together (for new entries to existing records). But it needs to be possible for the same name to appear more than once as a unique record (e.g. three individuals named John Smith).
This remark actually proves that you have design issues in your database.
A basic tenet of Database Design is to remove redundancy as much as possible. One of the reasons is actually to avoid having to update the same data in multiple places.
Another remark: you are using the Client's name as a Natural Key. Frankly, it is not a very good idea. Generally, you want to make sure that what constitutes a Primary key for a table is reliably unique over time.
Using people's names is generally the wrong choice because:
people change name, for instance in many cultures, women change their family name after they get married.
There could also have been a typo when entering the name and now it can be hard to correct it if that data is used as a Foreign Key all in different tables.
as your database grows, you are likely to end up with some people having the same name, creating conflicts, or forcing the user to make changes to that name so it doesn't create a duplicate.
The best way to enforce uniqueness of records in a table is to use the default AutoNumber ID field proposed by Access when you create a new table. This is called a Surrogate key.
It's not mean to be edited, changed or even displayed to the user. It's sole purpose is to allow the primary key of a table to be unique and non-changing over time, so it can reliably be used as a way to reference a record from one table to another (if a table needs to refer to a particular record, it will contain a field that will hold that ID. That field is called a Foreign Key).
The names you have for your tables are not precise enough: think of each table as an Entity holding related data.
The fact that you have a table called AllList means that its purpose isn't that well-thought of; it sounds like a catch-all rather than a carefully crafted entity.
Instead, if this is your list of clients, then simply call it Client. Each record of that table holds the information for a single client (whether to use plural or singular is up to you, just stick to your choice though, being consistent is hugely important).
Instead of using the client's name as a key, create an ID field, an Autonumber, and set it as Primary Key.
Let's also rename the "Social Work Register", which holds the Client's cases, simply as ClientCase. That relationship seems clear from your description of the table but it's not clear in the table name itself (by the way, I know Access allows spaces in table and field names, but it's a really bad idea to use them if you care at least a little bit about the future of your work).
In that, create a ClientID Number field (a Foreign Key) that will hold the related Client's ID in the ClientCase table.
You don't talk about the relationship between a Client and its Cases. This is another area where you must be clear: how many cases can a single Client have?
At most 1 Case ? (0 or 1 Case)
exactly 1 Case?
at least one Case? (1 or more Cases)
any number of Cases? (0 or more Cases)
Knowing this is important for selecting the right type of JOIN in your queries. It's a crucial part of the design assumptions when building your database.
For instance, in the most general case, assuming that a Client can have 0 or more cases, you could have a report that displays the Client's Name and the number of cases related to them like this:
SELECT Client.Name,
Count(ClientCase.ID) AS CountOfCases
FROM Client
LEFT JOIN ClientCase
ON Client.ID = ClienCase.ClientID
GROUP BY Client.Name
You've described your basic design a bit more, but that's not enough. Show us the actual table structures and the SQL of the queries you tried. From the description you give, it's hard to really understand the actual details of the design and to tell you why it fails and how to make it work.
I've been using Access to create simple databases for a while with great success, but have run into a problem I can't find an answer to.
We ship individualized serialized units to various end-users, and occasionally to resellers that stock them for end-users. I must keep track of which serial numbers end up with each end-users.
The first database I created to handle this recorded company information in one table using their account number as primary key, order information in a second table using the order number as the primary key and linked via the company name, and unit information in a third table with the serial number as the primary key and linked via the order number.
This worked very well until I had to account for these stock orders with a reseller. As it was structured, every unit was linked to one company via the sales order. The issue is that I may ship 20 units on one order to Company A, who then sells 5 to Company B and 3 to Company C.
I realized I needed to link the company name directly to the units, not the orders and have fixed that.
My issue now is simplicity in entering information in the form. My previous database involved the employee in our shipping department merely entering the sales order, selecting the customer name from a drop down menu, then scanning the serial numbers in a subform. This was to ensure simplicity and try to eliminate human error. He had only three things to input, and most of the input was done by scanning barcodes.
As it is currently structured now, the employees out in shipping would have to populate the company name for every record in the subform with the serial number and that complicates things in a way that is unacceptable. At the point of shipping, the company name will always be the same for every unit in the subform.
So.
How would I go about creating a form where the company name is entered once in the form, and automatically populates itself for every record in the subform? The caveat here is that I must also be able to go back occasionally and change the company name of individual units in an order without necessarily affecting the rest of the order. I suppose it starts out as a one-to-many relationship that then must be able to change.
I hope that makes sense.
I have looked for answers using various approaches with auto-fill and relationships and not preserving data integrity, but I feel the answer is just beyond my reach.
The only solution I can think of is to create another field in the unit table for the end-user, and perhaps write a formula that sets this default value as the company name from the order that shipped it. This seems unnecessarily complicated and redundant, there has to be a better way.
I have 200 users each user will eventually have a "reviewINFO" table with certain data.
Each user will have a review every 3 to 4 months
So for every review, it creates a new row inside the "reviewINFO" table.
This is where i'm stuck. I'm not sure if I need to serialize a table inside each row or not.
Example:
-> links
"USER1reviewINFO"-row1->USER1table1
-row2->USER1table2
-row3->USER1table3
-row4->USER1table4
-row5->USER1table5
"USER2reviewINFO"-row1->USER2table1
-row2->USER2table2
-row3->USER2table3
-row4->USER2table4
-row5->USER2table5
using this method it will make a couple of thousand rows within two years. And I think its harder to manage.
"Userxtablex" is a table with dynamic rows of children names,ages,boolean
What i'm think of doing is serialize each USERxtable into its corresponding row.
Please help as I would not like to make this complicate or inefficient
Generally, you should never have to serialize data of this nature into a table row to accomplish what your goal is (which I am assuming is an implicit link between a user and a review)
What you need to do is key the reviews by a user_id such that all the reviews are packaged in one table, and relate numerically back to the users table.
Assuming you have an AUTO_INCREMENT primary key in the user table, all you would need is a user_id field in the reviews table that represents what user the review relates to. There is no need for a separate structure for each user, if that's what you are suggesting. Reviews can have date fields as well, so you can perform queries for a specific year or window of time.
You can then use a JOIN query to select out your data set relating to a particular user or review, and apply the usual WHERE clause to determine what result set you want to fetch.
I have been working on a database that holds order numbers and order information. Previously I used a report that provided an order ID and a unique item ID for each item ordered. The item ID was the primary key as it was a uniquely assigned value.
This meant that one order # could have multiple items within it, each item identified by a unique item ID.
Now our requirements have changed to become more real time, which means the report that provided the unique item ID's has not run. As such I will need to generate my own unique item id's, but only within the same order #.
Additional information for those who use Amazon's MWS:
Previously I was using the Reports API to generate _GET_AMAZON_FULFILLED_SHIPMENTS_DATA_ to provide our fulfillment data while a 3rd party integrations company pulled the _GET_FLAT_FILE_ORDER_REPORT_DATA_ report to handle our merchant fulfilled orders. We are now looking to make our merchant fulfilled orders real-time using the Orders API, which unfortunately does not provide the orderItemId that is provided by the _GET_FLAT_FILE_ORDER_REPORT_DATA_ file. The problem I need to solve is related to the absence of that field.
Some sample data to work with would be:
Order-ID Item-ID Item
222-2212 1 redShirt
222-2216 1 redShirt
222-2212 2 blueShirt
222-2212 3 greenShirt
222-2218 1 noShirt
I would like to be able to something like:
SELECT * from order_data WHERE Order-ID like '222-2212';
and have all 3 items returned. The problem I have is I have no idea how to provide a unique auto-incremented number based upon the count of the Order-ID. I also want to avoid using a standard auto-incremented value across all data as I could then end up with duplicate orders and would need to try and filter using DISTINCT.
Does anyone have any ideas, pointers or suggestions on how I may accomplish this? I do have the luxury of redesigning the entire database from scratch so I am open to suggestions.
--EDIT--
I am currently following up with Amazon to determine if the orderItemId returned by the orders API is randomly generated. I will post more details here when I find out.
Turns out that the orderItemId is in fact a unique value. I was able to locate the documentation on Amazon's site under Confirming Multiple Shipments using Feeds. The statement states:
order-item-id Amazon.com's unique identifying number for an item in an order. This number is provided in your Orders Report. Note: This is not the same as the product ASIN. The order-item-id will differ from order to order.
I will be using this as my primary key, so I will not need to generate a random value as I expected this morning.