Database design: users and guests - mysql

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.

Related

How to model my database for a one-to-many relationship

I am learning backend development in Django and came across this problem.
Say I am designing a travel app:
I have two databases USER and TRIP with one-to-many relationship. i.e., each user can have multiple trips and each trip can be taken by only one user.
TRIP has a column trip-number. I would like to auto-increment this column for every row added into the TRIP database BUT the increment should be independent for each user starting from 1
TRIP table
user
trip-number
1
1
2
1
1
2
1
3
2
2
3
1
Something like that? I cannot auto-increment the whole column as it has to be unique for each trip taken by the user BUT the numbers can be same across different users.
Ideally I prefer to do this automatically on the server-end (sql) instead of writing a logic in the client. Any help would be appreciated. Thank you
Using trigger to update the trip_num column is one way to achieve the desired result but I would suggest not to use the triggers as it has many disadvantages. Few of them are as follows:
you will need trigger for insert/delete/update actions.
In insert trigger, you will have to assign trip_number per user.
In update trigger, you will have to check if user column is updated, if yes then you will have to arrange trip_number accordingly.
In delete trigger, you will have to arrange all the trip_num, if one of the record except last record of the user is deleted.
If two transactions occur at the same time for same the user then there will chances that triggers assign the same trip_num to different rows of the same user.
So, to avoid it, you can use the view as follows:
Create view vw_name as
Select t.*, -- use column names and remove trip_num column
Row_number() over (partition by user order by trip_date) as trip_num
From your_table t

mySql – How to search for available IDs

I have a mySQL table, which stores data of a user list and has an ID in unsigned tiny-int format (0 to 255 entries possible) as primary key. I enabled auto-increment in order to automatically set the key, which works fine so far.
When users log off I call ALTER TABLE sj_userlist AUTO_INCREMENT=1 which executes without errors.
However, the next logged in user still receives the ID+1 of the currently highest ID.
Example:
10 Users are online with the IDs 1,2,3,4,5,6,7,8,9,10
Users 1 and 2 to 9 log out - only ID 1 and 10 are still logged on
a new user logs in and receives ID 11 but I want him/her to get the 2
In case this behavior is correct, how can I achieve an alternative solution, which always starts at 1 incrementing untl the next available ID is found ?
Thanks in advance,
best
Alex
Possible solution.
Create a table for users registration. Define username column as unique.
Insert max amount of records into it according the datatype (0-255, for example).
When the user logs in and needs to register you use
UPDATE table
SET name = 'Current user name'
WHERE name IS NULL
ORDER BY id
LIMIT 1;
SELECT id
FROM table
WHERE name = 'Current user name';
This guarantee that user will get the least available number, and no interference/concurrence problems will occur.
When user log out then you use
UPDATE table
SET name = NULL
WHERE name = 'Current user name'
id is now free for re-use by the next user logged in.
If some problems occures on the client side, and user have not logged out correctly then his name will stay registered. But when he logged in the next time he will receive the same id - UPDATE will fail but SELECT will return non-freed id.
Nevertheless you must clear such old records periodically.

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.

MySQL update table 1 with table 2 data

Sorry for the ambiguous title.
I have two tables:
table 1: mailing_email
table 2 (dynamic table but for now is): membership
table 1 contains a list of all email accounts in the database and few ancillary fields such as name. It also has a column called communicate.
communicate is basically my terminology for subscribed. Any unsubscribe link will set communicate to false.
Both mailing_email and membership have a email and communicate column.
I need to write a query where the following happens:
mailing_email.communicate gets updated to the current status of membership.communicate where mailing_email.email = membership.email. If an email exists in mailing_email which does not exist in membership, the communicate field stays the same.
How would i go about doing this the fastest possible way? Each table will have thousands of rows this sync command would run often.
MySQL offers an update join syntax:
UPDATE mailing_email
JOIN membership ON mailing_email.email = membership.email
SET mailing_email.communicate = membership.communicate

Update existing values in database

I created a database table with 5 columns uniqueID (auto increment), name, college, mobile, event(check box of 12 event). So my question is each time a user registers the unique id increments and iI want another event to an already existing uniqueId, is there a possible way to add/update this without going all over to the database and editing it there?
OK, following the comments, I suggest you do the following.
You need two tables.
user
- userid (unique, auto-increment)
- name
- college
- mobile
event
- eventid (unique, auto-increment)
- userid (not-unique, connects to the user)
When a user registers, you create the user record and the first event record. Then when the user adds another event, you add another event record.
UPDATE:
I was trying to teach you slowly, but peterm is right in his comment. The best way is actually this:
user
- userid (unique)
- fields relevant only to the user
event
- eventid (unique)
- fields relevant to the event (e.g., date, place etc)
user_event
- userid
- eventid (where you have a unique key that includes two fields, userid and eventid)
You might also have a college record too...
But as I said, I was just trying to get you going in the right direction.