MySQL constrain transaction for entity must finish before another can begin - mysql

I have a table for guests, each guest with a unique name.
I have a table for guest_transactions with guest_id, status_id, arrived_time, left_time.
And a status table with a name column, populated with values (here, leaving, left).
I want to record guests as they come and go, but I'd like to have a constraint which prevents a guest from arriving twice before leaving. Is there a way to do this?

Related

Is there any constraint in SQL where I add a value that is a foreign key to one table, it removes that value(primary key) from another table?

I have two tables defined as:
dealership_inventory(vin, dealer_id, price, purchase_date)
where vin is the PK and dealer_id is the FK
transactions(transaction_id, dealer_id, customer_id, vin, cpurchase_date, price)
where transaction_id is PK and dealer_id,customer_id, and vin are FKs
Whenever I add a new transaction to the transactions table with an insert statement, I would like to remove that tuple with matching vin from the dealership_inventory table. Is this possible with some type of constraint?
You don't really need to do the removal of the VIN number from the inventory table. Instead, if you want to find out whether a vehicle be still available, just use an exists query, e.g.
SELECT di.*
FROM dealership_inventory di
WHERE NOT EXISTS (
SELECT 1
FROM transactions t
WHERE t.vin = di.vin
);
If, at some later point, the inventory table gets bogged down with items no longer available, you can run a batch job which moves these sold items to another table.

How to maintain multiple branches for a primary key (col1) and a json datatype column

I have a design question where I know that JSON is the best option but still facing issues with implementation.
Requirement:
I need to store business entity information. Attributes are (registration_NO (primary key), Address, phone number (multiple phone numbers), directors (multiple people) etc.
It is due to the one-to-many between registration_number and (phone number, and directors), I decided to go with jsonb datatype.
there are 2 conditions.
phone number, directors may be added, removed etc.
any new changes to the records need approval. Until approved, the old values will be displayed.
Problems I am facing:
say for example:
current record: Regno: directors, record_status (did not show phone number on purpose)
100: {John, Joe}, current; ok to display
when I add a new director, this entry must be a new branch of the registration# Primary key with status as "not yet approved" and therefore should not show up in queries.
100: {john, joe, jane}, updated; not yet approved.
however, when I update the row, the old value of directors is getting overwritten.
When I insert with status as "update; not yet approved", then it inserts a duplicate record for the registration#.
Ideally, I would like to have 2 branches for registration# 100 ; one approved to show, and one not approved to show.
How should I manage this? Any help is appreciated.
Rule of thumb: If your data has a predictable structure, you probably don't want to use a JSON column.
I would implement this with three tables. One table for the business entity, one for the phone numbers, and one for the directors. Something like this:
CREATE TABLE business_entity (
registration_no uuid,
address text,
PRIMARY KEY(registration_no)
);
CREATE TYPE status AS ENUM ('added', 'deleted');
CREATE TABLE business_entity_phone_number (
registration_no uuid,
phone_number text,
status status,
CONSTRAINT fk_business_entity_phone_number
FOREIGN KEY(registration_no) REFERENCES business_entity(registration_no)
);
CREATE TABLE business_entity_director (
registration_no uuid,
director text,
status status,
CONSTRAINT fk_business_entity_director
FOREIGN KEY(registration_no) REFERENCES business_entity(registration_no)
);
The status columns are there to track changes. So if a new phone number is added, we mark that row as "added" until it's approved, and if a row is deleted we leave it in place but mark it as "deleted" until it's approved.
Then, in order to query our business entities, we need only leave out "added" rows:
SELECT
be.registration_no,
address,
(
SELECT ARRAY_AGG(phone_number)
FROM business_entity_phone_number bepn
WHERE be.registration_no = bepn.registration_no
AND COALESCE(bepn.status, 'deleted') != 'added'
) as phone_numbers,
(
SELECT ARRAY_AGG(director)
FROM business_entity_director bed
WHERE be.registration_no = bed.registration_no
AND COALESCE(bed.status, 'deleted') != 'added'
) as directors
FROM business_entity be
Things this solution does not fully deal with:
Tracking changes to other fields in business_entity (it wasn't clear from the question if this is needed)
Updates to phone numbers/directors (or is adding/deleting enough?)
What happens when two users try to make conflicting changes?

MySQL click log by country, best approach

I'm planning to log referral clicks in mysql by the country of the IP.
Let's say my table is named referral_clicks and has the columns id, referral_id, country.
I have 2 approaches in mind now:
Create another column clicks which is set to +1 for every country / referral_id. This means that I would have to check first if the row for the specific referral_id and country already exists and if not, create it.
Insert a new row for every request. My concern here is, that the table might geht messy and too big, as might get very much referral requests.
What would be the best approach now for something like that, or is there evern a better approach?
Use INSERT ... ON DUPLICATE KEY UPDATE.
I suggest you create a table with the following columns.
id (autoincrement)
referral_id
country
clickdate
clicks
I suggest you create a unique index of (referral_id,country,clickdate).
Then, I suggest you use the following SQL each time you want to log a click:
INSERT INTO referral_clicks (referral_id, country, clickdate, clicks)
VALUES ('whatever', 'whatcountry', CURDATE(), 1)
ON DUPLICATE KEY UPDATE clicks=click+1
This will start a new row for each referral id, for each country, for each date. If the row already exists it will increment clicks for you.

MySQL movie reservation system design part 2

This is similar to another question but not entirely the same.
My aim is to design a movie reservation system. A user could click on one or more empty seats for a movie schedule to reserve them. But he needs to make a payment before 15mins is up, otherwise the reserved seats would have to be automatically given up for other users.
I have the following pseudo MySQL :
Table Movie:
id int primary key,
name varchar,
.....
Table MovieSched:
movie_id foreign key refers to Movie,
sched_id int primary key,
showtime datetime, // date and time of schedule
count_signup int, // number of sign ups
max_size int // max number of seats
Table MovieSchedSignUp:
sched_id foreign key refers to MovieSched,
user_id foreign key refers to User,
signup datetime // datetime of signup
Every movie schedule has a max_size of users who can sign up. To register a user, I insert a row in MovieSchedSignUp with the current date and time.
A few constraints naturally arise from the requirements:
Due to possible inconsistency between the interface and database, I need to inform a user A when there are not enough seats available when A tries to reserve seats. (for e.g., another user B could have bought all the seats right before A.)
I need to atomically insert a row in MovieSchedSignUp while ensuring the schedule is not "overbooked" (count_signup <= max_size) as well as updating count_signup at the same time.
I need to ensure payment is made within 15mins, otherwise the reserved seats have to be freed.
My thoughts are:
Have extra columns in MovieSchedSignUp to keep track of when payment is made.
Use a transaction, but how do I return information about whether there are enough seats or not?
Have a batch job running in the background to delete the "expired" rows in MovieSchedSignUp.
What is the most efficient way to go about doing this? Any other thoughts? Don't really want to use a batch job, but is there any other way out?
I think in this situation you are going to have to use a transaction.
Start the transaction
Insert the records to be added to a temp table
Do a join between the temp table, MovieSched and MovieSchedSignUp to
check the number of records (combined temp and MovieSchedSignUp) isn't greater than max size.
If OK then do the insert
If OK them commit the transaction, if not then roll back the
transaction.

MySQL - Table Implementation

I had to implement the following into my database:
The activities that users engage in. Each activity can have a name with up to 80 characters, and only distinct activities should be stored. That is, if two different users like “Swimming”, then the activity “Swimming” should only be stored once as a string.
Which activities each individual user engages in. Note that a user can have more than one hobby!
So I have to implement tables for this purpose and I must also make any modifications to existing tables if and as required and implement any keys and foreign key relationships needed.
All this must be stored with minimal amount of storage, i.e., you must choose the appropriate data types from the MySQL manual. You may assume that new activities will be added frequently, that activities will almost never be removed, and that the total number of distinct activities may reach 100,000.
So I already have a 'User' table with 'user_id' as my primary key.
MY SOLUTION TO THIS:
Create a table called 'Activities' and have 'activity_id' as PK (mediumint(5) ) and 'activity' as storing hobbies (varchar(80)) then I can create another table called 'Link' and use the 'user_id' FK from user table and the 'activity_id' FK from the 'Activities' table to show user with the activities that they like to do.
Is my approach to this question right? Is there another way I can do this to make it more efficient?
How would I show if one user pursues more than one activity in the foreign key table 'Link'?
Your idea is the correct, and only(?) way.. it's called a many to many relationship.
Just to reiterate what you're proposing is that you'll have a user table, and this will have a userid, then an activity table with an activityid.
To form the relationship you'll have a 3rd table, which for performance sake doesn't require a primary key however you should index both columns (userid and activityid)
In your logic when someone enters an activity name, pull all records from the activity table, check whether entered value exists, if not add to table and get back the new activityid and then add an entry to the user_activity table linking the activityid to the userid.
If it already exists just add an entry linking that activity id to the userid.
So your approach is right, the final question just indicates you should google for 'many to many' relationships for some more info if needed.