DatabaseDesign for a Traveller - mysql

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.

Related

select `one` where location = one, all or multiple choices

I have multiple creatures in database(mysql) and 6 different areas. Currently all creatures appear in everywhere, but I would like to make some appear in one location or multiple selected locations.
The way I would solve it right now is that every location has id from 1 to 9. Graveyard = 1, Swamp = 2, Forest = 3, Caves = 4. Then have it in the creatures table saved as field where_creature_appears
where
12 appears only in Graveyard and Swamp;
23 appears only in Swamp and Forest;
124 appreas only in Graveyard, Swamp, Caves;
etc
and with sql I would use WHERE LIKE % $location_id %. If I have more locations then I could extend to letters as well.
Question is would there be better way to do it, or simpler, or smarter. Happy if someone can point in the useful direction with links or ideas.
Thanks for any help!
You can do it by having one more table that would be many-to-many table.
Basically, in that table you will have the information if that creature is in that specific area and the opposite. Because, many creatures can be in many areas, and many areas can have many different creatures.
That table should look like this:
Table name: creature_area
creature_id | area_id
----------------------
1 | 2
1 | 3
3 | 2
5 | 1
Then, you will be able to query all the areas for the specific creature, and also all the creatures for the specific area, like this:
Give me IDs of all areas for this creature is in:
SELECT area_id FROM creature_area WHERE creature_id = ....
Give me IDs of all creatures that are in this area:
SELECT creature_id FROM creature_area WHERE area_id = ....
Then you can do all kind of JOINs to get the names of those creature/areas and such.
More details on how to achieve this is here: https://dzone.com/articles/how-to-handle-a-many-to-many-relationship-in-datab
I hope this helps.

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 matching phone calls from two tables

I've been trying to solve an apparently simple problem for a couple of days now, and I can't seem to figure it out flawlessly, no matter which attempt I take.
I've two simple Tables, each with 3 cols: call_date, call_time, caller_id all of them are self-explanatory.
The first table contains inbound calls, the second one contains outbound calls.
After receiving an inbound call, the corresponding outbound call should be made within 30 minutes. So far so good, no problem here, but this is where it gets a little bit tricky:
There can be multiple inbound calls from the same caller_id in the inbound table.
Only calls that have a minimum of 30 Minutes distance to the previous relevant call are regarded as valid calls. So when someone calls four times, let's say at 08:00, at 08:15, at 08:31 and at 09:31, there are three valid calls: 08:00, 08:31 and 09:31. So after each valid call you have to wait 30 minutes again in order for the next call to be valid.
The outbound table can also contain none, one, or multiple calls to the same number, all of which must be matched as closely as possible to the incoming calls.
I tried various approaches to this problem, but all of them are not 100% accurately, always leaving one or more calls unmatched or not marked as valid etc, and my head is starting to spin a lil bit.
Right now I build a huge table from my inbound call table, adding numerous columns for the previous_calltime and next_calltime so I can calculate the minutes between the time stamps. A second approach I took, was to create seperate tables with the first and last calls each day of each number etc, but something always does not add up.
Here's a sample of my data tables, in- and outbound are the same.
+----+-----------+----------+----------+
| id | call_date | call_time|caller_id
+----+-----------+----------+----------+
| 1 | 2013-06-01| 08:00 | 12345
+----+-----------+----------+----------+
| 2 | 2013-06-01| 08:20 | 12345
+----+-----------+----------+----------+
| 3 | 2013-06-01| 08:30 | 12345
+----+-----------+----------+----------+
| 4 | 2013-06-01| 08:32 | 555-999
+----+-----------+----------+----------+
| 5 | 2013-06-01| 08:47 | 555-999
+----+-----------+----------+----------+
Maybe someone can point me in a rough direction which approach I should take.
Any suggestions are appreciated.
P.s. I am trying a 100% MySQL based approach here, but theoretically I could also make use of PHP, just in case someone thinks this is a pain to do in pure SQL and it could be much more easy using PHP.
Initial code to play with.
This is ignoring dates (for now) but should give you a list of the valid calls. Not sure it will be that quick, but it might be an idea to use it to populate a list somewhere of valid calls (or to mark the inbound calls as valid or not).
Using you test data above it gives the results I would expect:-
SELECT Sub1.*,
#valid := if(#PrevCallerId != Sub1.caller_id OR (TIME_TO_SEC(call_time) - #PrevValidCall) >= 1800, "valid", "invalid") AS valid_call,
#PrevValidCall := if(#valid = "valid", TIME_TO_SEC(Sub1.call_time), #PrevValidCall),
#PrevCallerId := Sub1.caller_id
FROM
(
SELECT *
FROM Inbound
ORDER BY caller_id
) Sub1
CROSS JOIN (SELECT #PrevValidCall:= 0, #PrevCallerId := "", #valid := "") Sub2

MySQL, how to repeat same line x times

I have a query that outputs address order data:
SELECT ordernumber
, article_description
, article_size_description
, concat(NumberPerBox,' pieces') as contents
, NumberOrdered
FROM customerorder
WHERE customerorder.id = 1;
I would like the above line to be outputted NumberOrders (e.g. 50,000) divided by NumberPerBox e.g. 2,000 = 25 times.
Is there a SQL query that can do this, I'm not against using temporary tables to join against if that's what it takes.
I checked out the previous questions, however the nearest one:
is to be posible in mysql repeat the same result
Only gave answers that give a fixed number of rows, and I need it to be dynamic depending on the value of (NumberOrdered div NumberPerBox).
The result I want is:
Boxnr Ordernr as_description contents NumberOrdered
------+--------------+----------------+-----------+---------------
1 | CORDO1245 | Carrying bags | 2,000 pcs | 50,000
2 | CORDO1245 | Carrying bags | 2,000 pcs | 50,000
....
25 | CORDO1245 | Carrying bags | 2,000 pcs | 50,000
First, let me say that I am more familiar with SQL Server so my answer has a bit of a bias.
Second, I did not test my code sample and it should probably be used as a reference point to start from.
It would appear to me that this situation is a prime candidate for a numbers table. Simply put, it is a table (usually called "Numbers") that is nothing more than a single PK column of integers from 1 to n. Once you've used a Numbers table and aware of how it's used, you'll start finding many uses for it - such as querying for time intervals, string splitting, etc.
That said, here is my untested response to your question:
SELECT
IV.number as Boxnr
,ordernumber
,article_description
,article_size_description
,concat(NumberPerBox,' pieces') as contents
,NumberOrdered
FROM
customerorder
INNER JOIN (
SELECT
Numbers.number
,customerorder.ordernumber
,customerorder.NumberPerBox
FROM
Numbers
INNER JOIN customerorder
ON Numbers.number BETWEEN 1 AND customerorder.NumberOrdered / customerorder.NumberPerBox
WHERE
customerorder.id = 1
) AS IV
ON customerorder.ordernumber = IV.ordernumber
As I said, most of my experience is in SQL Server. I reference http://www.sqlservercentral.com/articles/Advanced+Querying/2547/ (registration required). However, there appears to be quite a few resources available when I search for "SQL numbers table".

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