Combine Access tables - ms-access

Before you think this is a question that has already been answered, hear me out.
I inherited an Access MDB file. It has 2 tables (actually 4 but I'm only really concerned with 2). One is a member table with an AutoNumber field. The second table has the same fields but the ID field is simply Number (not AutoNumber). This second table gets the names of people when they "retire".
The problem now is some people want to return. I can't copy them back in because they will get a new ID number and all of the other report data (that I didn't mention before) is keyed to their original ID number which is still unique between the two tables.
What I think I'd like to do is temporaily turn off the AutoNumber field long enough to allow me to merge the data from the "retired" table, then turn AutoNumber back on. But Access won't let me do that because the AutoNumber ID is tied to other tables and various reports. (I guess I do care about the other tables.)
This answer is close, Adding records with old ids that were generated using auto number in access, but focuses on 1 row. I have plenty. Same with this answer: Keep value of autonumber column when importing into Microsoft Access database.
I'm thinking the second answer is really close, but I don't know how to use docmd.RunSQL.
If this is simple and I'm just missing the obvious, I'm willing to admit being a NOOB with Access.

Access will let you INSERT a row with a number for an autonumber field as long as the number you're inserting doesn't conflict with any of the existing values. And since "their original ID number which is still unique between the two tables", it sounds like that is your situation.
Consider these 2 tables:
tblMembers
id fname
1 Anne
3 Cathy
tblRetired
id fname
2 Bob
4 David
This INSERT statement (the Access query designer calls it an "append query") will add the tblRetired rows to tblMembers.
INSERT INTO tblMembers ( id, fname )
SELECT r.id, r.fname
FROM tblRetired AS r;
This is tblMembers after executing that INSERT ...
id fname
1 Anne
2 Bob
3 Cathy
4 David

Related

SQL - Make sure a column is unique over multiple rows?

I have a table in MySQL, which represents a user, that should be able to add up to three phone numbers to his account. So of course no phone number, that already exists should be able to be registered again. I made all three columns unique, but the problem is, that you can still enter as number 2 a number, that someone else entered as his first number. So I was wondering, if there is an SQL possibility to ensure, that one row is unique with other rows too or I need to solve this issue with querying, if there exists already a member with this number programmatically.
MemberID
Main number
Number 2
Number 3
1
123
456
789
2
456
123
567
So this example should be forbidden.
So as Strawberry assumed the best solution is to normalize the table. Since every member as 1 to n numbers, the numbers should be an own entity.
The resulting solution would be to remove the number fields out of the member table and create a new table, which looks the following:
Member_Id (Foreign Key)
Priority
Number
1
1
234
...
...
...
Then a unique constraint on the number column ensures, that no number is used by two members.

MS-Access show only items that meet multiple criteria

I am new to Access and I am looking for a solution that is beyond the ability of the others in my company and may be beyond what access can do.
I have the following fields.
Date: Last Name: First Name: Test1: Test2: Test3:
I am looking for the following to happen.
On any single date a user may test multiple times.
If the user passes all three tests do not show any records with fails or any duplicate passes.
If the user fails any of the three tests, but has multiple failed records only show one.
If the user has the statement "NotUsed" in any field, but a pass in any other keep a single record for that date.
Thank You,
First, you need a primary key column in order to be able to easily and unambiguously identify each record. In Access this is easily achievable with a Autonumber column. Also, in the table designer, click the key symbol for this column. This creates a primary key index. A primary key is a must for every table.
Let us call this column TestID and let's assume that the table is named tblTest.
The problem is that your condition refers to several records; however, SQL expects a WHERE clause that specifies the conditions for each single record. So let’s try to reformulate the conditions:
Keep the record with the most passes for each user.
Keep records with "NotUsed" in any test field.
The first condition can be achieved like this:
SELECT First(TestID)
FROM
(SELECT TestID, [Last Name], [First Name] FROM tblTest
ORDER BY IIf(Test1='pass',1,0) + IIf(Test2='pass',1,0) + IIf(Test3='pass',1,0) DESC)
GROUP BY [Last Name], [First Name]
This gives you the TestID for each user with the most passes. Now, this is not the final result yet, but you can use this query as a subquery in the final query
SELECT * FROM tblTest
WHERE
Test1='NotUsed' OR Test2='NotUsed' OR Test3='NotUsed' OR
TestID IN ( <place the first query here...> )
Is this what you had in mind?
Another thought is about normalization. Your table is not normalized. You are using your table like an Excel sheet. As your database grows you'll get more and more into trouble.
You have two kinds of non-normalization.
One relates to the fact that each user's first name and last name might occur in several records. If, in future, you want to add more columns, like user address and phone number, then you will have to repeat these entries for each user record. It will become increasingly difficult to keep this information synchronized over all the records. The way to go is to have at least two tables: a user table and a test table where the user table has a UserID as primary key and the test table has this UserID as foreign key. Now a user can have many test records but still always has only one unique user record.
The other one (non-normalization) occurs because you have 3 Test fields in a single record. This is less of a problem if your tests always have the same structure and always require 3 tests per date, but even here you have to fall back to the "NotUsed" entries. There are several ways to normalize this, because a database can have different degrees of normalization. The tree ways:
Only one test table with the fields: TestID (PK), UserID (FK), Date, Result, TestNumber.
A test day table with the fields: TestDayID (PK), UserID (FK), Date + a test result table with the fields: TestResultID (PK), TestDayID (FK), Result, TestNumber
Then you can combine the two previous with this addition: Instead of having a TestNumber field, introduce a lookup table containing information on test types with the fields: TestTypeID (PK), TestNo, Description and in the other tables replace the column TestNumber with a column TestTypeID (FK).
See: How to normalize a table using Access - Part 1 of 4 or look at many other articles on this subject.

Syncronizing entries in a table according to a user array in MySQL

I have the following situation. The entries in a table come from a list of users for a particular id. That way id 7 has 3 rows for, say, 2, 6, 7 (these three are unique ids for a user data table). To clarify the table looks like this.
ID USERID KEYID
Where KeyID is auto_inc and is the table's primary key.
These entries come from a multiple select field. So a user might want to delete user 2 and add user 8. So the function that needs to update the table gets the array 8,6,7 for id 7. The quick way I found to do the syncronization is simply to delete every entry in the table for ID 7 and add 3 new entries of the from (ID,USERID) (7,8) (7,6) (7,7).
However I don't know if this is how it's supposed to be. Is there a better way? Also this methods drives the keyid up really fast (for every modification in the table, basically). Is that a problem? I'm an newbie with these things, so please be patient.
Well, you can delete rows selectively like this:
DELETE FROM my_table WHERE user1 = 7 AND user2 NOT IN (8,6,7)
where (8,6,7) is list of pairs (7,6),(7,8),(7,7) , that should be preserved, kept, not deleted, and it will delete all other pairs (7,?)
Your next question may be "Then how to add pairs while not making duplicities?"
You will first need to teach your table what duplicity is. By adding unique key on pair of fields (user1,user2). That would forbid duplicities. Now, when inserting new rows that may be already there, use "INSERT IGNORE" to ignore such exception and simply, continue on.

Database design: users and guests

I have two types of people on my site, users and guests. Virtually they are the same, except for creation/auth processes.
At the moment I have two tables:
t_users
userId[PRIMARY, AUTOINC] username[UNIQUE]
t_guests
guestId[PRIMARY, AUTOINC] userId
When somebody enters the site, script does the following:
1) creates new guest record by inserting a new row to t_guests
2) adds new record to t_users, using guestId generated on previous step (guest username = “Guest guestId”)
3) updates guest record setting userId assigned on step 2
I feel this database design to be just awful, because it contains many vulnerabilities. For example, if username "Guest xyz" already exists in t_users table, step 2 will fail and step 3 will assign wrong value to the userId (depending on implementation it’ll be 0 or guestId, assigned on step 1).
Actually I only need t_guests table for its auto increment feature to generate unique usernames for guests. Is there a way to use just one consolidated table and register guests using single query?
UPDATE: I can do the following to insert guests in a single table:
SELECT #mg := IFNULL(MAX(guestId), 0) + 1 FROM t_users;
INSERT INTO t_users (guestId) VALUES(#mg);
But I can't be sure, that nobody inserts a new guest record in t_users between execution of those two statements. And I can't make guestId unique, because real users will have it equal to zero.
If you just have 1 table with"
userID, username, type
for the username you could use your script to generate a Guid and use that as the username, or someother random variable. If you use a GUID it is virtually impossible that you get 2 guids that collide.
Also if you do have 2 usernames that collide if you make sure that the username column has to be unique then the insert will fail and you could just try again.
You definitely aught to just have 1 table here.

How to handle fragmentation of auto_increment ID column in MySQL

I have a table with an auto_increment field and sometimes rows get deleted so auto_increment leaves gaps. Is there any way to avoid this or if not, at the very least, how to write an SQL query that:
Alters the auto_increment value to be the max(current value) + 1
Return the new auto_increment value?
I know how to write part 1 and 2 but can I put them in the same query?
If that is not possible:
How do I "select" (return) the auto_increment value or auto_increment value + 1?
Renumbering will cause confusion. Existing reports will refer to record 99, and yet if the system renumbers it may renumber that record to 98, now all reports (and populated UIs) are wrong. Once you allocate a unique ID it's got to stay fixed.
Using ID fields for anything other than simple unique numbering is going to be problematic. Having a requirement for "no gaps" is simply inconsistent with the requirement to be able to delete. Perhaps you could mark records as deleted rather than delete them. Then there are truly no gaps. Say you are producing numbered invoices: you would have a zero value cancelled invoice with that number rather than delete it.
There is a way to manually insert the id even in an autoinc table. All you would have to do is identify the missing id.
However, don't do this. It can be very dangerous if your database is relational. It is possible that the deleted id was used elsewhere. When removed, it would not present much of an issue, perhaps it would orphan a record. If replaced, it would present a huge issue because the wrong relation would be present.
Consider that I have a table of cars and a table of people
car
carid
ownerid
name
person
personid
name
And that there is some simple data
car
1 1 Van
2 1 Truck
3 2 Car
4 3 Ferrari
5 4 Pinto
person
1 Mike
2 Joe
3 John
4 Steve
and now I delete person John.
person
1 Mike
2 Joe
4 Steve
If I added a new person, Jim, into the table, and he got an id which filled the gap, then he would end up getting id 3
1 Mike
2 Joe
3 Jim
4 Steve
and by relation, would be the owner of the Ferrari.
I generally agree with the wise people on this page (and duplicate questions) advising against reusing auto-incremented id's. It is good advice, but I don't think it's up to us to decide the rights or wrongs of asking the question, let's assume the developer knows what they want to do and why.
The answer is, as mentioned by Travis J, you can reuse an auto-increment id by including the id column in an insert statement and assigning the specific value you want.
Here is a point to put a spanner in the works: MySQL itself (at least 5.6 InnoDB) will reuse an auto-increment ID in the following circumstance:
delete any number rows with the highest auto-increment id
Stop and start MySQL
insert a new row
The inserted row will have an id calculated as max(id)+1, it does not continue from the id that was deleted.
As djna said in her/his answer, it's not a good practice to alter database tables in such a way, also there is no need to that if you have been choosing the right scheme and data types. By the way according to part od your question:
I have a table with an auto_increment field and sometimes rows get deleted so auto_increment leaves gaps. Is there any way to avoid this?
If your table has too many gaps in its auto-increment column, probably as a result of so many test INSERT queries
And if you want to prevent overwhelming id values by removing the gaps
And also if the id column is just a counter and has no relation to any other column in your database
, this may be the thing you ( or any other person looking for such a thing ) are looking for:
SOLUTION
remove the original id column
add it again using auto_increment on
But if you just want to reset the auto_increment to the first available value:
ALTER TABLE `table_name` AUTO_INCREMENT=1
not sure if this will help, but in sql server you can reseed the identity fields. It seems there's an ALTER TABLE statement in mySql to acheive this. Eg to set the id to continue at 59446.
ALTER TABLE table_name AUTO_INCREMENT = 59446;
I'm thinking you should be able to combine a query to get the largest value of auto_increment field, and then use the alter table to update as needed.