How do you store undefined number of things in MySQL? - mysql

Say, we have data of person that have some possessions. The person can have nothing or have anything. What is the proper way to store data like this?
As far as I know, MySQL doesn't provide a way to store array as a data type. If it does, maybe it will be something like this:
CREATE TABLE person (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
possessions ARRAY NOT NULL
);

I believe what you would be looking for is three tables (or two if each possession can only be owned by one person).
Table Person has PersonId (INT PK Identifier) and PersonName (along
with any other person attributes)
Table Possession has PossessionId
(INT PK Identifier) and PossessionName (along with any other
possession attributes)
Table PersonPossession has PersonId and
PossessionId representing that the person has that possession.
This is a fairly simple design for an m:n relationship (i.e. a person has some number (possibly 0) of possessions, and possessions have some number of "owners")
If each possession can only be owned by a single person you can go down to two tables by eliminating table PersonPossession and just having PersonId being a column of the Possessions table

Related

Mysql Storing multi values in a column

I have a tables called userAccounts userProfiles and usersearches.
Each userAccount may have multiply Profiles. Each user may have many searches.
I have the db set up working with this. However in each search there may be several user profiles.
Ie, each user account may have a profile for each member of their family.
They then want to search and include all or some of their family members in their search. The way i would kinda like it to work is have a column in user searches called profiles and basically have a list of profileID that are included in that search. (But as far as i know, you can't do this in sql)
The only way i can think i can do this is have 10 columns called profile1, profile2 ... profile10 and place each profileid into the column and 0 or null in the unused space. (but this is clearly messy )
Creating columns of the form name1...nameN is a clear violation of the Zero, One or Infinity Rule of database normalization. Arbitrarily having ten of them is not the right approach, that's an assumption that will prove to be either wildly generous or too constrained most of the time. Since you're using a relational database, try and store your data relationally.
Consider the schema:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
name VARCHAR(255),
UNIQUE KEY index_on_name (name)
);
CREATE TABLE profiles (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
user_id INT NOT NULL,
name VARCHAR(255),
email VARCHAR(255),
KEY index_on_user_id (user_id)
);
With that you can create zero or more profile records as required. You can also add or remove fields from the profile records without impacting the main user records.
If you ever want to search for all profiles associated with a user:
SELECT ... FROM profiles
LEFT JOIN users ON
users.id=profiles.user_id
WHERE users.name=?
Using a simple JOIN or subquery you can easily exercise this relationship.

Relational database and PHP: one-to-many relations with multiple one-tables

Let’s assume there are some rows in a table cars, and each of these rows has an owner. If this owner were always a person (conveniently situated in a table persons), this would be your standard one-to-many relation.
However, what if the owner could not only be a person, but also a company (in a table companies)? How would this relationship be modeled and how would it be handled in PHP?
My first idea was to create a column person and a column company and check that one of them always stays NULL, while the other is filled – however, that seems somewhat inelegant and becomes impractical once there is a higher number of possible related tables.
My current assumption would be to not simply create the foreign key as an integer column person in the table, but to create a further table called tables, which gives IDs to the tables, and then split the foreign key into two integer columns: owner_table, containing the ID of the table (e.g. 0 for persons and 1 for companies), and owner_id, containing the owner ID.
Is this a viable and practical solution or is there some standard design pattern regarding such issues? Is there a name for this type of problem? And are there any PHP frameworks supporting such relations?
EDIT: Found a solution: Such structures are called polymorphic relations, and Laravel supports them.
There are multiple ways to do it.
You can go with two nullable foreign keys: one referencing company and the other user. Then you can have a check constraint which assure you one is null. With PostgreSQL:
CREATE TABLE car{
<your car fields>
company_id INT REFERENCES car,
person_id INT REFERENCES person,
CHECK(company_id IS NULL AND person_id IS NOT NULL
OR company_id IS NOT NULL AND person_id IS NULL)
};
Or you can use table inheritance (beware their limitations)
CREATE TABLE car_owner{
car_owner_id SERIAL
};
CREATE TABLE company{
<company fields>
} INHERITS(car_owner);
CREATE TABLE person{
<person fields>
} INHERITS(car_owner);
CREATE TABLE car{
<car fields>
car_owner_id INT REFERENCES car_owner
};

Creating a Table in SQL, where each tuple can have mutiple values

I m try to make a Table using Create Table in SQL,
where a person can work at multiple places, and a place can have multiple person working on it,
this is what i m trying, i m sure its not correct
create table ( person char(15), place char(15), salary int)
now since a person can work in multiple places, i m confused should the tuple place has multiple values,
if yes. how do i do it
Thanks in advance
It is called a n to m relation. Use 3 tables
persons table
-------------
id int
name varchar
places table
------------
id int
name varchar
place_persons table
-------------------
place_id int
person_id int
You should create three separate tables:
"persons"
int ID (primary key, auto-increment)
varchar username
varchar email ... (all other info needed)
"places"
int ID (primary key, auto-increment)
varchar name
etc.
And the third table gives you the relationship between the two:
"person_places" (or place_persons, depends on what you like)
int ID (primary key, auto-increment)
int place_id (linked to the ID of the "places" entry)
int person_id (linked to the ID of the "persons" entry)
This way, every time a person starts working in a new place, you just add an entry to the "person_places". Same thing when they leave a place, or a place goes out of business or whatever, you just need to touch the "person_places" table.
Also, this way, one person can work in several places, just like one place can have several people working in it.
This is not normalized but it is ok to use this as you have only 3 columns and normalization will add more headache of joins and extra columns to define relationship.
suppose PersonA works in both PlaceA and PlaceB. PersonB also works in both the places but on different salaries then your data will be like this
insert into Yourtable values
('PersonA','PlaceA',1000),
('PersonA','PlaceB',2000),
('PersonB','PlaceA',1100),
('PersonB','PlaceB',1200),
('PersonC','PlaceA',1000)
and if you want to know that how many places PersonA works then you query will be
select place from YourTable where person = 'PersonA'
This way you don't need to save multiple values in same tuple.

automatically retrieve data from related tables

I'm working with a database that contains a table called model_meta which contains metadata about all the various models in use by the application. Here is the relevant data structure:
CREATE TABLE model_meta (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(64),
oo INT(11),
om INT(11),
mo INT(11),
mm INT(11),
INDEX (name)
);
CREATE TABLE inventory (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
type VARCHAR(255),
customers_id INT(11)
);
CREATE TABLE customers (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
contact VARCHAR(255)
);
The columns oo, om, mo, and mm in the model_meta table contain a comma-separated list of ids to which that model has the specified relationship (i.e. one-to-one, one-to-many, etc.).
When a client requests data, all I'm given is the name of the table they're requesting (e.g. 'inventory') - from that, I need to determine what relationships exist and query those tables to return the appropriate result set.
Given a single variable (let's call it $input) that contains the name of the requested model, here are the steps:
get model metadata: SELECT model_meta.* FROM model_meta WHERE model_meta.name = $input;
determine which, if any, of the relationship columns (oo, om, mo, mm) contain values - keeping in mind that they can contain a comma-separated list of values.
use the values from step 2 to determine the name of the related model(s) - for the sake of example, let's just say that only mo contains a value and we'll refer to it as $mo.
So: SELECT model_meta.name FROM model_meta WHERE model_meta.id = $mo;
Let's call this result $related.
Finally, select data from the requested table and all tables that are related to it - keeping in mind that we may be dealing with a one-to-one, one-to-many, many-to-one, or many-to-many relationship. For this specific example:
In psuedo-SQL: SELECT $input.*, $related.* FROM $input LEFT JOIN $related ON ($related.id = $input.$related_id);
This method uses three separate queries - the first to gather metadata about the requested table, the second to gather the names of related tables, and the third to query those tables and return the actual data.
My question: Is there an elegant way to combine any of these queries, reducing their number from from 3 to 2 - or even down to one single query?
The real goal, of course, is to in some way automate the retrieval of data from related tables (without the client having to knowing how the tables are related). That's the goal.

Database structure: Would this structure work with this m:m?

Here is my issue: (Using MySQL)
I have 2 entities called 'shops' and 'clients'. I also have a M:M table between 'clients' and 'shops' called 'clients_shops' (CakePHP naming convention). The reason I am doing it this way is that this is a SaaS application where 'clients' may have many 'shops' and 'shops' will definitely have many 'clients'.
However, I don't want to give a shop the ability to UPDATE/DELETE a 'client' record since what really needs to happen is that the 'shop' will EDIT/DELETE that 'client' from their own records, rather than from a master 'clients' table which is managed by the 'clients'.
Anyway, using this structure a 'shop' can run a query on the 'clients_shops' table to get a list of their clients and a 'client' can run a query a get a list of their 'shops'. Good so far...
So far, the database looks like this:
table.clients
client_id (PK, AI, NN)
table.shops
shop_id (PK, AI, NN)
table.clients_shops
clients_shops_id (PK,AI,NN)
client_id (FK)
shop_id (FK)
The ORM looks like this:
shops hasMany clients_shops
clients hasMany clients_shops
So far so good (I think...) but here is my question. Let's say that there is a third table named 'trips'. The 'trips' table stores information on individual bookings whereby a 'client' will make reservations for a 'trip' that is provided by a 'shop'. This is where my brain is getting mushy. How should I set this relationship up?
Is it this way:
table.trips
trips_id (PK,AI,NN)
clients_shops_id (FK) [which would contain keys for both the shop and the client]
Or is there a better way to do this, like another table that uses clients.client_id AND clients_shops.clients_shops_id.
Thanks in advance to anyone that actually read this whole thing!
Unless it's required by your ORM, you don't need a surrogate foreign key for clients/shops and everything that refers to it.
Make a composite PRIMARY KEY instead and refer to it from elsewhere:
CREATE TABLE clients_shops
(
client_id INT NOT NULL,
shop_id INT NOT NULL,
PRIMARY KEY (client_id, shop_id)
);
CREATE TABLE trips
(
trip_id INT NOT NULL PRIMARY KEY,
client_id INT NOT NULL,
shop_id INT NOT NULL,
trip_data …,
CONSTRAINT fk_trips_clients_shops
FOREIGN KEY (client_id, shop_id)
REFERENCES clients_shops
);
This model assumes that you maintain clients/shops relationships separately from the clients' transactions and not let clients buy from the shops unless they are "related".
Probably you want the relationship to appear automatically whenever a trip is ordered by a client from a shop. In this case, you only need the second table, and the first table is a mere
SELECT DISTINCT client_id, shop_id
FROM trips
Here is the Logical Diagram to handle what you are looking for. Depending on your requirements you can change the non-identying relationships (Client::Trip & Shop::Trip) to identifying relationships. If you do though I would limit it to only changing the Shop::Trip to identifying though. Also make changes to the Cardinality as you see fit.
I would probably make the trips table like this:
table.trips
trip_id (PK)
shop_id (FK to shops)
client_id (FK to clients)
other_trip_column_etc
I would not reference the m-m table clients_shops from the trips table - just reference the shop and client tables with individual foreign keys.
The clients_shops table represents the current relationship between a client and a shop. The trip should not depend on these relationships, because they could potentially change in the future, and you probably wouldn't want the trip's data to change over time - it should be a transactional record that specifies exactly what shop, client, and trip was scheduled at that given time, regardless of the current relationship between that client and shop.