modeling issue with field with 4 values (1 or more) - mysql

lets say I have an account object in my application, which currently represented as:
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (accountId)
);
Now, Account object need to also have Solution field...and Status have 4 different possible values:
Solution1, Solution2, Solution3, Solution4
What would be the right way to represent it in the database?
Account can have few statuses, and status can have few accounts...
So at first I thought create in the db table of Solutions and than have another table to hold the relationship, but its seems too complicated for a field that have only 4 possible values...

Create a junction table to represent the relationships between accounts and solutions:
CREATE TABLE account_solution (
accountId int NOT NULL,
solutionId int NOT NULL
PRIMARY KEY (accountId, solutionId)
)
For your solution table, since there are only 4 values, you might be able to take advantage of MySQL's enum type, e.g.
CREATE TABLE solution
solutionId int NOT NULL PRIMARY KEY,
status ENUM('Solution1', 'Solution2', 'Solution3', 'Solution4')
);

You can use set Mysql SET type
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
status set('Solution1','Solution2','Solution3','Solution4') NOT NULL,
PRIMARY KEY (accountId)
);
And if you want to select a specific status
SELECT *
FROM `Account`
WHERE FIND_IN_SET( 'Solution2', `status` ) >0

Related

Generate unique key for users with same email-address

We have a table with orders of customers like:
CREATE TABLE `orders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`number` varchar(20) NOT NULL,
`ordered` datetime DEFAULT NULL,
`email` varchar(255) NOT NULL,
...
);
The table is already filled with data. I need to add a field:
`user` int(10) unsigned NOT NULL,
which contains a unique number for each customer. A customer is defined by the same email-address, so all orders with the email 'test#example.com' should get a 1, with 'something_else#example.com' should get a 2 and so on.
For this 'user'-number it doesn't matter if it starts with 1 or is somehow incrementing, it just should be different for every email-address.
Is there a way to do this in one SQL-statement? I know how to do it with some php-code for example, but we where curious if it's possible just with SQL. We know it would be a better design if there was a table "customer", but it's not our design, we just trying to fix the worst things ;)
It's not possible to do what you describe in one SQL statement.
Even if you didn't care to make the user id unique per email, your ALTER TABLE wouldn't work. You show adding a column that is NOT NULL but has no DEFAULT. So what value is it supposed to add to the table, given that the table has rows in it? It can't use NULL, and it has no DEFAULT value. You can't add the column as an AUTO_INCREMENT because you already have an id column that is AUTO_INCREMENT, and MySQL doesn't allow a table to have two such columns.
Here's the way I'd do it:
CREATE TABLE customers (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL
);
INSERT INTO customers (email)
SELECT DISTINCT email FROM orders;
ALTER TABLE orders ADD COLUMN user_id INT UNSIGNED; -- this allows NULLs until we fill it
UPDATE orders JOIN customers USING (email)
SET orders.user_id = customers.id;
Before the next step, make sure that it has populated orders.user_id the way you think is correct. Once you drop the orders.email column, there's no undo. It would be a good idea to make a backup first.
ALTER TABLE orders DROP COLUMN email,
MODIFY COLUMN user_ID INT UNSIGNED NOT NULL; -- disallow NULLs from now on

How to create a public id?

I have a database. As you can see the primary key is an auto_increment and is also unique. I read that publically sharing a row's primary key of a table to the public is unsafe. I want to assign each row in customers a unique ID that I can publically share. How can I do this without having to specify each time what the public_id is in the INSERT statement? The database should automatically find a unique ID to assign to that row just like it does for id because of auto_increment.
CREATE TABLE customers (
id int primary key auto_increment,
name varchar(32) not null,
-- public_id (an ID I can give to the public to uniquely identify this row
);
INSERT INTO customers (name) VALUES ('Bob'), ('Sarah'), ('Bob');
Well, here's one way:
CREATE TABLE customers (
id int primary key auto_increment,
name varchar(32) not null,
public_id char(36) not null unique default uuid()
);
Note that the manual says:
Warning
Although UUID() values are intended to be unique, they are not necessarily unguessable or unpredictable. If unpredictability is required, UUID values should be generated some other way.
So this is simple, and maybe will float your goat, but we can also try better:
CREATE TABLE customers (
id int primary key auto_increment,
name varchar(32) not null,
public_id char(24) not null unique default to_base64(random_bytes(18))
);
This will be a nice and dense identifier, but it will have characters + and / which don't play well with URLs. You can encode them, of course, but if you want to go one lazier, you can also do this:
CREATE TABLE customers (
id int primary key auto_increment,
name varchar(32) not null,
public_id char(32) not null unique default hex(random_bytes(16))
);
Mind you, the identifier will get quite a bit longer this way.
To get the best of both worlds, we can do this, at the expense of a really long default value:
CREATE TABLE customers (
id int primary key auto_increment,
name varchar(32) not null,
public_id char(24) not null unique default replace(replace(to_base64(random_bytes(18)), '+', '_'), '/', '-')
);
Also note that messing around with MD5()/SHA()/SHA1()/SHA2() is no better than just generating a random hex string with a given length.

How should I create a table based in the following requirements? [SQL]

I have got the following JSON file:
"vehicle_number" : 91,
"pit_stops" : [ {
"pit_in_elapsed_time" : 1874.0926,
"pit_out_elapsed_time" : 0.0
}, {
"pit_in_elapsed_time" : 1992.9723,
"pit_out_elapsed_time" : 0.0
}, {
"pit_in_elapsed_time" : 2862.2129,
"pit_out_elapsed_time" : 0.0
} ],
My table has to keep the following value:
vehicle
pit_int_elapsed_time
pit_out_elapse_time
How do I create a table based on this??
create table pitstop (
vehicle varchar(50) not null,
inTime varchar(50) not null,
outTime varchar(50) not null,
constraint pk_id primary key(inTime, outTime))
I am not sure if this would be the ideal way of create the table?
Regards
EDIT
I have been thinking of creating 2 main tables. One for the vehicles (vehicleID as pk, pitstopFK as foreign key).
create table vehicles (
vehicle varchar(50) primary key not null
pitstops_fk int not null );
Also the pitstops table:
create table pitstops (
id int primary key autoincrement not null,
inTime varchar(50) not null,
outTime varchar(50) not null,
constraint u_time UNIQUE (inTime, outTime))
vehicles ----- pitstops ( 1 to many)
It's hard to say much without a better understanding of the problem you're trying to solve, but I would say:
if vehicle ID is always an integer, an unsigned int will generally perform better than treating it as text
using a SQL date type for the inTime and outTime columns will allow you to use SQL time/date operations. If the timestamps represent real-world times consider DATETIME or TIMESTAMP, if they are elapsed seconds since the start of a race or something like that, a floating point numeric type would probably be a better choice.
the combination of inTime and outTime doesn't make sense as a primary key, since as you note in the comment it is not necessarily unique. In thinking about designating a primary key, don't (just) think about uniqueness, but about how you'd want to refer to a pitstop event from other tables. In the case I would probably suggest a synthetic auto-incremented unsigned int as a primary key.
First of all, if it is a time you want to store in your database i wouldn't use varchar. Instead try to use Float or Real.
The next thing is, that you should take your vehicle in your primary key as well.
I also would recommend to introduce a ID to your Database.
Something like this:
CREATE TABLE pitstop (
ID int NOT NULL AUTO_INCREMENT,
vehicle varchar(50) NOT NULL,
inTime float NOT NULL,
outTime float NOT NULL,
constraint pk_id primary key(ID, vehicle))

MySQL table linking 1:n

So first up I'm not sure if this is a double post or not because I don't know how the exact approach or feature is called and if it even exist.
I know that MySQL has a feature called joins
My plan is to link two MySQL tables in relation 1:n one is t_user the other one t_event.
t_user:
CREATE TABLE t_user (
uId INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(25) NOT NULL,
...
)
t_event:
CREATE TABLE t_event (
eId INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40) NOT NULL,
date DATETIME NOT NULL,
members ???,
...
)
I want the users to "subscribe" to the events and get stored in the members column as a list (?). This would be no problem if only one user would subscribe to one event. But I have no idea how to setup the t_event table to store more than one user and how to query for all the events a user has "subscribed" for.
This is usually done via third table:
CREATE TABLE t_eventsusers (
eId INT(6),
uId INT(6)
)

What is the best way to have a varchar primary key column with an auto-increment?

I would like to create some tables in MySQL. One table would be for users, one for topics, one for comments, and so on.
I need each table to have its own ID column in the following format:
USERS table: ID column
Values:
USR00001
USR00002
USR00003
..
..
USR99999
where as topics table would have IDs like:
TPC00001
TPC00002
TPC00003
similarly, the comments table would have the following IDs:
CMT00001
CMT00002
I tried to use UNIQUE key but did not work: (inspired by this answer)
CREATE TABLE `users` (
`ID` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,
`firstname` VARCHAR(100) NOT NULL ,
`lastname` VARCHAR(100) NOT NULL ,
`email` VARCHAR(100) NOT NULL ,
PRIMARY KEY (`ID`)
UNIQUE KEY ( 'USR' + `ID`)
);
Can it be done using triggers (Before Insert) maybe?
Please note that I don't want to handle the insertion of the primary keys on the application level. I would prefer the database engine to handle all the work for that.