I have a table request_track
that saves various security related requests.
Unsuccessful and successful logins have to be saved each and the entry in the request_track
table marked as such. Now I struggle to find a good name (for #2) and wanted to know what you guys would do at my place.
I thought about the following options:
Make two TINYINT
columns: is_login_success
and is_login_failure
default 0
.
Pros
sum(is_login_success)
and sum(is_login_failure)
Cons
1
or both with 0
. It is technically possible though to set both with 1
which would cause unpredictable issues in the code.Something like one is_login_success
TINYINT
default null
.
1
would indicate that it was a successful login request, 0
would mean unsuccessful request and null
means it's neither.
Pros
Cons
0
means explicitly that it's a failure.I could make a is_login
ENUM('success', 'failure')
default null
Pros
Cons
My favourite is clearly #3, but I don't want to use two SELECT
queries. I'm sure though it's possible in only one. I should have paid more attention in class.
You don't need two queries to fetch the number of successes/failures for any of these cases.
Option 1
Use the SUM
function once for each column.
CREATE TABLE request_track (
request_id INT NOT NULL AUTO_INCREMENT,
is_login_success TINYINT NOT NULL,
is_login_failure TINYINT NOT NULL,
PRIMARY KEY ( request_id )
);
SELECT SUM( is_login_success ) AS num_success, SUM( is_login_failure ) AS num_failure FROM request_track;
num_success num_failure 13 2
Option 2
Use the SUM
function once for each possible value. Use the CASE
function to determine the value to use for each row.
CREATE TABLE request_track (
request_id INT NOT NULL AUTO_INCREMENT,
is_login_success TINYINT,
PRIMARY KEY ( request_id )
);
SELECT SUM(CASE WHEN is_login_success = 1 THEN 1 ELSE 0 END) AS num_success, SUM(CASE WHEN is_login_success = 0 THEN 1 ELSE 0 END) AS num_failure, SUM(CASE WHEN is_login_success IS NULL THEN 1 ELSE 0 END) AS num_unknown FROM request_track;
num_success num_failure num_unknown 13 2 3
Option 3
Same approach as option 2.
CREATE TABLE request_track (
request_id INT NOT NULL AUTO_INCREMENT,
is_login ENUM('success', 'failure') DEFAULT NULL,
PRIMARY KEY ( request_id )
);
SELECT SUM(CASE WHEN is_login = 'success' THEN 1 ELSE 0 END) AS num_success, SUM(CASE WHEN is_login = 'failure' THEN 1 ELSE 0 END) AS num_failure, SUM(CASE WHEN is_login IS NULL THEN 1 ELSE 0 END) AS num_unknown FROM request_track;
num_success num_failure num_unknown 13 2 3
Regardless, your approach should consider
How easy is it to maintain the data?
As you point out, the first option has the potential for invalid data to get into your
table. If a row ends up with 1
in both is_login_success
and is_login_failure
then you've lost data.
The second option also has the possibility to lose data. What happens if a query inserts 2
into is_login_success
? Without a constraint, the database won't mind, but the row won't make any business sense.
The third option prevents both of these mistakes. There is only one column so a given row cannot be in conflicting states. The column has a pre-determined number of possible values so it cannot be in an invalid state.
How easy is it to maintain the table?
Adding a single column to each row is not complicated, but you mention that this table will be used to track different types of requests. Will you need a new is_<request type>
column for each type? Your table has the potential to become quite wide quite quickly.
You might consider cutting each row down to an identifier, a type, and a status. The meaning of the status is allowed to differ between types and can be defined in an external table. When you need to add or remove a type, you are adding or removing an external table instead of adding or removing columns on your table.