What would be an ideal mysql database strcture for a multi-level subscription web application? - mysql

Currently I am developing a system that accepts multi-level subscribers. With Laravel 5.8, MySQL.
The idea is,
An user (A) will signup with the system.
This user can suggest N number of his friends (B,C,D,...).
And B, C, D,.. can suggest N number of friends them-self after signup with the system.
Now A have his subscribers and his subscriber's subscribers.
Note, B or C or D,.. also can include A as their friend.
A
|
/ / / \ \ \
B C D L M N
| |
/ | \ |
L A D |
|
/ | \
K L M
|
/ / / \ \ \
A B C P Q R
therefore:
A's network is the major network.
both B and M can access all of the members because they have A in their list.
L don't have any list
can access all users because M is friend of D and M is friend with A.
The Structure cannot be considered as hierarchical.
I guess, Many to many relationship and join table concept needs to be implemented.
MySQL Procedure needs to be used to retrieve information.
Requirements
I need to store this relational structure in mysql DB
I should be able to retrieve unique users for any given users (MySQL Procedure).
I hope the I can get a possible suggestions and advise to build this system properly. Thank you.

You could store tree by adding parent_id column. Than, use cache to store which users (for example) user C is subscribed to (M, D, A).

It sounds like a task for graph database. Mysql is not really a great solution to be used here. You 100% will have problems with perfomance. As option, you can store only relationships in graph database (column ids), and retrieve actual data from mysql.
I know that i am a bit late, but someone can find this question through google.

Related

Joining and selecting multiple tables and creating new column names

I have very limited experience with MySQL past standard queries, but when it comes to joins and relations between multiple tables I have a bit of an issue.
I've been tasked with creating a job that will pull a few values from a mysql database every 15 minutes but the info it needs to display is pulled from multiple tables.
I have worked with it for a while to figure out the relationships between everything for the phone system and I have discovered how I need to pull everything out but I'm trying to find the right way to create the job to do the joins.
I'm thinking of creating a new table for the info I need, with columns named as:
Extension | Total Talk Time | Total Calls | Outbound Calls | Inbound Calls | Missed Calls
I know that I need to start with the extension ID from my 'user' table and match it with 'extensionID' in my 'callSession'. There may be multiple instances of each extensionID but each instance creates a new 'UniqueCallID'.
The 'UniqueCallID' field then matches to 'UniqueCallID' in my 'CallSum' table. At that point, I just need to be able to say "For each 'uniqueCallID' that is associated with the same 'extensionID', get the sum of all instances in each column or a count of those instances".
Here is an example of what I need it to do:
callSession Table
UniqueCallID | extensionID |
----------------------------
A 123
B 123
C 123
callSum table
UniqueCallID | Duration | Answered |
------------------------------------
A 10 1
B 5 1
C 15 0
newReport table
Extension | Total Talk Time | Total Calls | Missed Calls
--------------------------------------------------------
123 30 3 1
Hopefully that conveys my idea properly.
If I create a table to hold these values, I need to know how I would select, join and insert those things based on that diagram but I'm unable to construct the right query/statement.
You simply JOIN the two tables, and do a group by on the extensionID. Also, add formulas to summarize and gather the info.
SELECT
`extensionID` AS `Extension`,
SUM(`Duration`) AS `Total Talk Time`,
COUNT(DISTINCT `UniqueCallID`) as `Total Calls`,
SUM(IF(`Answered` = 1,0,1)) AS `Missed Calls`
FROM `callSession` a
JOIN `callSum` b
ON a.`UniqueCallID` = b.`UniqueCallID`
GROUP BY a.`extensionID`
ORDER BY a.`extensionID`
You can use a join and group by
select
a.extensionID
, sum(b.Duration) as Total_Talk_Time
, count(b.Answered) as Total_Calls
, count(b.Answered) -sum(b.Answered) as Missed_calls
from callSession as a
inner join callSum as b on a.UniqueCallID = b.UniqueCallID
group by a.extensionID
This should do the trick. What you are being asked to do is to aggregate the number of and duration of calls. Unless explicitly requested, you do not need to create a new table to do this. The right combination of JOINs and AGGREGATEs will get the information you need. This should be pretty straightforward... the only semi-interesting part is calculating the number of missed calls, which is accomplished here using a "CASE" statement as a conditional check on whether each call was answered or not.
Pardon my syntax... My experience is with SQL Server.
SELECT CS.Extension, SUM(CA.Duration) [Total Talk Time], COUNT(CS.UniqueCallID) [Total Calls], SUM(CASE CS.Answered WHEN '0' THEN SELECT 1 ELSE SELECT 0 END CASE) [Missed Calls]
FROM callSession CS
INNER JOIN callSum CA ON CA.UniqueCallID = CS.UniqueCallID
GROUP BY CS.Extension

database schema one column entry references many rows from another table

Let's say we have a table called Workorders and another table called Parts. I would like to have a column in Workorders called parts_required. This column would contain a single item that tells me what parts were required for that workorder. Ideally, this would contain the quantities as well, but a second column could contain the quantity information if needed.
Workorders looks like
WorkorderID date parts_required
1 2/24 ?
2 2/25 ?
3 3/16 ?
4 4/20 ?
5 5/13 ?
6 5/14 ?
7 7/8 ?
Parts looks like
PartID name cost
1 engine 100
2 belt 5
3 big bolt 1
4 little bolt 0.5
5 quart oil 8
6 Band-aid 0.1
Idea 1: create a string like '1-1:2-3:4-5:5-4'. My application would parse this string and show that I need --> 1 engine, 3 belts, 5 little bolts, and 4 quarts of oil.
Pros - simple enough to create and understand.
Cons - will make deep introspection into our data much more difficult. (costs over time, etc)
Idea 2: use a binary number. For example, to reference the above list (engine, belt, little bolts, oil) using an 8-bit integer would be 54, because 54 in binary representation is 110110.
Pros - datatype is optimal concerning size. Also, I am guessing there are tricky math tricks I could use in my queries to search for parts used (don't know what those are, correct me if I'm in the clouds here).
Cons - I do not know how to handle quantity using this method. Also, Even with a 64-bit BIGINT still only gives me 64 parts that can be in my table. I expect many hundreds.
Any ideas? I am using MySQL. I may be able to use PostgreSQL, and I understand that they have more flexible datatypes like JSON and arrays, but I am not familiar with how querying those would perform. Also it would be much easier to stay with MySQL
Why not create a Relationship table?
You can create a table named Workorders_Parts with the following content:
|workorderId, partId|
So when you want to get all parts from a specific workorder you just type:
select p.name
from parts p inner join workorders_parts wp on wp.partId = p.partId
where wp.workorderId = x;
what the query says is:
Give me the name of parts that belongs to workorderId=x and are listed in table workorders_parts
Remembering that INNER JOIN means "INTERSECTION" in other words: data i'm looking for should exist (generally the id) in both tables
IT will give you all part names that are used to build workorder x.
Lets say we have workorderId = 1 with partID = 1,2,3, it will be represented in our relationship table as:
workorderId | partId
1 | 1
1 | 2
1 | 3

MySQL - Best approach to ensure unique values across multiple rows

I have 3 tables:
Molecule:
id
Atom:
id
MoleculeAtom: # Composite primary key
molecule_id
atom_id
My goal is to ensure that no combination of atoms which make up a molecule, are repeated. For example, the water molecule, I would store two rows in the MoleculeAtom table; 1 row for a hydrogen atom and 1 row for an oxygen atom. As you can see, I need to ensure that no other molecule has JUST hydrogen and oxygen, even though there may be other molecules which include hydrogen and oxygen.
At this point I have a query which identifies which molecules includes either hydrogen or oxygen, and only having 2 atoms in the MoleculeAtom table.
SELECT
m.id, m.name, (SELECT count(*) from molecule_atom where molecule_id = m.id group by molecule_id) as atomCount
FROM
molecule AS m
INNER JOIN
molecule_atom AS ma ON ma.molecule_id = m.id
WHERE
ma.atom_id IN (1,2)
HAVING atomCount = 2;
Which returns (demonstrative snippet):
+----+----------------------------+-----------+
| id | name | atomCount |
+----+----------------------------+-----------+
| 53 | Carbon Dioxide | 2 |
| 56 | Carbon Monoxide | 2 |
+----+----------------------------+-----------+
(I know, that both CO and CO2 have the same exact atoms, in differing quantities, but dis-regard that, as I am tracking the quantities as a another column in the same table.)
As of now I am pulling the above results and checking their atom_ids via PHP, which means I have to issue a separate query for each molecule, which seems inefficient, so I was looking to see if it's possible to do this checking using strictly SQL.
Excuse any mistakes which may be chemical related, it's been a long time since chem101.
What you are asking for is a table-level constraint and these are not available in MySQL. In SQL-92 standard, there is ASSERTION, which is actually even more general (a constraint across more than 1 table). See the asnwers in this question: Why don't DBMS's support ASSERTION for details and for info about some products (MS-Access) that have such functionality with limitations.
In MySQL, you could try with a trigger to imitate such a constraint.
Update:
Firebird documentation says it allows subqueries in CHECK constraints.
A unique index might be helpful on the molecule_atom table. That would prevent duplicates at that level. You're still going to need to do some checks via SQL statements. Another option depending on the size of your list would be to load it in memory in a hash table and then run the checks from there.
The idea here is to find pairs of molecules whose lists of atoms are not the same:
select m1.molecule_id as m1id, m2.molecule_id as m2id
from molecule_atom as m1, molecule_atom as m2,
(select atom_id from molecule_atom as m where m.molecule_id=m1id) as m1a,
(select atom_id from molecule_atom as m where m.molecule_id=m2id) as m2a,
where m1id < m2id and (((m1a - m2a) is not null) or ((m2a - m1a) is not null))
As ypercube mentioned, MySQL doesn't support assertions, so I ended writing a query to find all molecules having at least one of the atoms which belong to the new molecule I am trying to create, and having the same number of atoms. After querying for matches, the application steps through each molecule and determines if they have the same exact atoms as the new molecule. Query looks like this (assumes I am trying to create a new molecule with 2 atoms):
SELECT
m.id,
m.name,
(SELECT GROUP_CONCAT(ma.atom_id) FROM molecule_atom AS ma WHERE ma.molecule_id = m.id GROUP BY ma.molecule_id HAVING (SELECT COUNT(ma.atom_id)) = 2) AS atoms
FROM
molecule AS m
INNER JOIN
molecule_atom AS mas ON mas.molecule_id = m.id
WHERE
mas.atom_id IN (1,2)
Then in code (PHP) I do:
foreach ($molecules as $molecule) {
if (isset($molecule['atoms'])) {
$diff = array_diff($newAtomIds, explode(',', $molecule['atoms']));
// If there is no diff, then we have a match
if (count($diff) === 0) {
return $molecule['name'];
}
}
}
Thanks for everyone's response.

DatabaseDesign for a Traveller

I'm currently having problems designing a database. I'm building a small car sharing plattform and im quite unsure how to store 'sharing offers'.
I have people travelling from A to D (via B, C)
A → B → C → D
And i've ppl travelling from C to D.
I thought about splitting the first trip into subtrips (A→B, B→C, C→D). With a "join" on B i could find connections from A → C. But with more intermediate steps, this would become quite slowly (I assume), keep in mind that you shouldn't change the driver/car during one ride.
I read something about 'nested sets', to build up a tree. But I'm not sure if this approach would fit for my problem, as i don't have a root (and i've no clue how to traverse that tree in sql). At the moment i dont know wherelse to start. If you confirm the use of nested sets, i'll dive into that.
But I appreciate any other ideas or suggestion
ps. this is my first post, i hope i got everything right :)
How about one row per stop during a trip, including the order number of the stop? Like this:
trip | stop | place
-----+------+------
1 | 1 | A
1 | 2 | B
1 | 3 | C
1 | 4 | D
That way you can easily find trips that go e.g. from A to C:
SELECT t.trip
FROM trips t
JOIN trips s ON (
t.trip = s.trip AND
t.place = "A" AND
s.place = "C" AND
t.stop < s.stop
);
This way the query will always be the same, regardless of subtrips.

MySQL: How to pull information from multiple tables based on information in other tables?

Ok, I have 5 tables which I need to pull information from based on one variable.
gameinfo
id | name | platforminfoid
gamerinfo
id | name | contact | tag
platforminfo
id | name | abbreviation
rosterinfo
id | name | gameinfoid
rosters
id | gamerinfoid | rosterinfoid
The 1 variable would be gamerinfo.id, which would then pull all relevant data from gamerinfo, which would pull all relevant data from rosters, which would pull all relevant data from rosterinfo, which would pull all relevant data from gameinfo, which would then pull all relevant data from platforminfo.
Basically it breaks down like this:
gamerinfo contains the gamers basic
information.
rosterinfo contains basic information about the rosters
(ie name and the game the roster is
aimed towards)
rosters contains the actual link from the gamer to the
different rosters (gamers can be on
multiple rosters)
gameinfo contains basic information about the games (ie
name and platform)
platform info contains information about the
different platforms the games are
played on (it is possible for a game
to be played on multiple platforms)
I am pretty new to SQL queries involving JOINs and UNIONs and such, usually I would just break it up into multiple queries but I thought there has to be a better way, so after looking around the net, I couldn't find (or maybe I just couldn't understand what I was looking at) what I was looking for. If anyone can point me in the right direction I would be most grateful.
There is nothing wrong with querying the required data step-by-step. If you use JOINs in your SQL over 5 tables, we sure to have useful indexes on all important columns. Also, this could create a lot of duplicate data:
Imagine this: You need 1 record from gamerinfo, maybe 3 of gameinfo, 4 ouf of rosters and both 3 out of the remaining two tables. This would give you a result of 1*3*4*3*3 = 108 records, which will look like this:
ID Col2 Col3
1 1 1
1 1 2
1 1 3
1 2 1
... ... ...
You can see that you would fetch the ID 108 times, even if you only need it once. So my advice would be to stick with mostly single, simple queries to get the data you need.
There is no need for UNION just multiple JOINs should do the work
SELECT gameinfo.id AS g_id, gameinfo.name AS g_name, platforminfoid.name AS p_name, platforminfoid.abbreviation AS p_abb, rosterinfo.name AS r_name
FROM gameinfo
LEFT JOIN platforminfo ON gameinfo.platforminfoid = platforminfo.id
LEFT JOIN rosters ON rosters.gameinfoid = gameinfo.id
LEFT JOIN rosterinfo ON rosterinfo.id = rosters.rosterinfoid
WHERE gameinfo.id = XXXX
this should pull all info about game based on game id
indexing on all id(s) gameinfoid, platformid, rosterinfoid will help on performance