Recommend to track all logins, update login table, or both? - mysql

Currently I am having a hard time deciding/weighing the pros/cons of tracking login information for a member website.
Currently
I have two tables, login_i and login_d.
login_i contains the member's id, password, last login datetime, and total count of logins. (member id is primary key and obviously unique so one row per member)
login_d contains a list of all login data in history which tracks each and every time a login occurs. It contains member's id, datetime of login, ip_address of login. This table's primary key is simply an auto-incremented INT field, really purposeless but need a primary and the only unique single field (an index on the otherhand is different but still not concerned).
In many ways I see these tables as being very similar but the benefit of having the latter is to view exactly when a member logged in, how many times, and which IP it came from. All of the information in login_i (last login and count) truthfully exists in login_d but in a more concise form without ever needing to calculate a COUNT(*) on the latter table.
Does anybody have advice on which method is preferred? Two tables will exist regardless but should I keep record of last_login and count in login_i at all if login_d exists?
added thought/question
good comment made below - what about also tracking login attempts based on a username/email/ip? Should this ALSO be stored in a table (a 3rd table I assume).

this is called denormalization.
you ideally would never denormalize.
it is sometimes done anyway to save on computationally expensive results - possibly like your total login count value.
the downside is that you may at some point get into a situation where the value in one table does not match the values in the other table(s). of course you will try your best to keep them properly up to date, but sometimes things happen. In this case, you will possibly generate bugs in application logic if they receive an incorrect value from one of the sources.
In this specific case, a count of logins is probably not that critical to the successful running of the app - so not a big risk - although you will still have the overhead of maintaining the value.

Do you often need last login and count? If Yes, then you should store it in login_i aswell. If it's rarely used then you can take your time process the query in the giant table of all logins instead of storing duplicated data.

Related

Should a session table be cleared off from the records after a user logs out?

I am using a MySql table to store a session record for the current logged in user. Once the user logs off, I update few fields in the same record and flags(revoked) it that it should not be used again. So for every LogIn a new record is created. This serves my purpose, but it turns out that the table is going to grow huge.
What should be the standard approach for storing Sessions? Should the ones, which are revoked be stored in a separate table, or should they be deleted or left in the same table?
I consider leaving the data in the same session table. While querying for a particular record, I query with two fields : (idPeople (not unique) and revoked (0 or 1)), for example SELECT * FROM session WHERE idPeople = "someValue" AND revoked = 0. and then update the record if needed while the user is, logged in or kogging out. Will the huge size of table affect this? or MySql will handle this? And what are other ramifications for this which I am unable to see?
First, it may be a good idea to add a unique field to your table (e.g. SESSION_ID, which could be a running auto-increment number), define this field as a unique ID, and use it to quickly find the record to be updated (i.e. revoke=1).
Second, this type of table always triggers the question you are asking, and the best answer can only be given after you assess and answer some preliminary questions, for instance:
When you wish to check the activities of a user, how far into the past does it make sense to go? One month? One year?
What is the longest period that you may wish to keep this information available (even using non routine queries to retrieve?
What type of questions (queries) I expect to be asked on this table?
One you answer those questions, you can consider the following options:
Have a routine process that would run once a day (at midnight or any other time your system can afford it) which would delete rows whose timestamp is older than, say, one month (or any other period suiting your needs), OR
Same as above but would first copy those records to an "history" table,
Change the structure of your table to a more efficient one, by adding some fields (as suggested above) and indices that would provide good answers for your "SELECT" needs.

What's the best/correct way to store data in mysql?

I'm working now on a project that involves many users and they're log in time/log out time (and summary) details. To be able to watch after their presence.
My question is what is possibly the best way to store tat data? (if we talk about hundreds or maybe thousands of users)
1. To make an DB that contains a table for each user, there it has all the dates and hours?
2. To make one big table which contains all this data?
Thanks.
A table for each user is a weird approach.
Make a table for ALL users, which is the correct way to go.
Then make a table called actions with the user_id as a FOREIGN KEY, and two more columns: type and time.
When the user logs in, add a new row to the actions table with type = 1 (login) and when he logs out, add a type = 2 (logout).
Using numbers instead of strings is better since it reduces database weight.
Repeating the same string is costy.
The type column must be a INT type.
The time column can have CURRENT_TIMESTAMP as the default value, since it will log the action when it has happened.
See a example fiddle with schema and query

Access query is duplicating unique records / Linked table issues

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.

When to use a relational database structure?

I'm creating a file hosting service, but right now I am creating the account email activation part of registering. So I had to come up with a database structure.
And right now it's:
users
id
first_name
last_name
email
password
since
active
hash_activate
But I can do it like a relational database too:
users
id
first_name
last_name
email
password
since
activation
id
user_id
hash
active
What would be the best way to go about it? And why?
If every person has only one activation hash active at at time, then it's feasible to store it in same table with users.
However, one advantage of separating it is that users only have an activation hash for a brief period of time, so to keep the user records smaller, you could store the hashes in a separate table. Keeping the user records small keeps it more performant. In this case, you wouldn't have active column. You'd just delete inactive hashes.
If you do store the activation columns in the user table, just be sure to select the columns by name. E.g. in most cases, you'll want do this:
SELECT id, first_name, last_name, email, password
FROM users
Instead of:
SELECT *
FROM users
You'd only want to select the activation columns when you needed them.
The second would only be sensible if one user could have multiple activations. You don't say whether this is true or false, so I couldn't possibly advise you.
If activations are a temporary thing, or having a hash defines someone as active, then make them different. Otherwise, that really won't matter.
However, neither is necessarily more or less relational than the other, without much more information. If you put a unique constraint on the combination of values in each row, and set each column up with a NOT NULL constraint, your first one would be quite relational.
You use a relational design when correctness of data, over time, is as important, if not more important, than what the application does with that data, and/or when data structure correctness/consistency is critical to the correct operation of an application, but might not necessarily be guaranteed by the application's own operation.

Which MySQL schema would is optimal for this type of system

Assuming a system similar to Netflix where members create a wish list of movies and, based on their type of plan, one, two, or more of those movies in their list turn into orders, which one of the following schemas makes more sense?
A controls table storing the following columns:
controls(memberid, currentMoviesAtHome, moviesAtHomeLimit, currentMonthlyMovies, monthlyMoviesLimit)
The user does not actually decide when the order is created as that depends on their account controls. A daily function will go through the customers and their controls and choose ones where currentMoviesAtHome < moviesAtHomeLimit AND currentMonthlyMovies < monthlyMoviesLimit ...
A separate accounts table linked to a plans plans table:
accounts(memberid, planid, currentMoviesAtHome, currentMonthlyMovies)
plans(planid, moviesAtHomeLimit, monthlyMoviesLimit)
The second option, having the ACCOUNTS and PLANS tables, is normalized so it would be my recommendation.
Additionally, these tables:
MOVIES
WISHLIST
movie_id (primary key, foreign key to MOVIES.movie_id)
account_id (primary key, foreign key to ACCOUNTS.account_id)
is_onsite
The is_onsite would be a boolean to determine if the movie has been sent to the client. If it has, value should be set to 1. Use this to sum to know if the account is at or under their plan limit. When videos are returned, only delete the rows that have is_onsite set to 1.
A daily function will go through the customers and their controls and choose
This doesn't answer your question but I thought I'd mention that your design is suboptimal. Rather than polling, as you describe above, you're much better off deciding what to do on-demand; that is, there will obviously be a time in your application's use where the limit values will be updated. What you should do is fire some kind of event at that time and consume the event that will decide whether or not to send out another movie.
Polling on a daily basis will not scale.
Firing and handling an event will not only be faster but it will be easier to maintain in the long run. Good luck.