New to MySQL and need help manipulating user data in table 1 into the structure shown in table 2.
table 1
table 2
A user session is defined as a period of user activity with requests at least every 30 minutes. A session ends when the user has been inactive for over 30 minutes.
Does anyone know how to write mysql code that transforms table 1 into 2?
The following code can be used to create the log table:
CREATE TABLE log
( user_id int, request_timestamp datetime);
INSERT INTO log
VALUES
(1, '2014-10-26 10:51:18'), (1, '2014-10-26 10:52:20'), (1, '2014-10-26 11:15:03'), (1, '2014-10-26 11:39:18'), (1, '2014-10-26 15:01:18'), (1, '2014-10-26 15:01:21'), (1, '2014-10-27 21:22:19'),
(2, '2014-10-15 12:19:01'), (2, '2014-10-15 12:19:12'), (2, '2014-10-15 12:19:45'), (2, '2014-10-15 12:20:03'), (2, '2014-10-17 14:55:13'), (2, '2014-10-17 14:55:19'),(2, '2014-10-17 14:55:22')
;
Schema
CREATE TABLE log
( user_id int, request_timestamp datetime);
INSERT INTO log
VALUES
(1, '2014-10-26 10:51:18'), (1, '2014-10-26 10:52:20'), (1, '2014-10-26 11:15:03'), (1, '2014-10-26 11:39:18'), (1, '2014-10-26 15:01:18'), (1, '2014-10-26 15:01:21'), (1, '2014-10-27 21:22:19'),
(2, '2014-10-15 12:19:01'), (2, '2014-10-15 12:19:12'), (2, '2014-10-15 12:19:45'), (2, '2014-10-15 12:20:03'), (2, '2014-10-17 14:55:13'), (2, '2014-10-17 14:55:19'),(2, '2014-10-17 14:55:22');
First we will give the following a name just to visualize it:
Note below the 1800 means 30 min * 60 sec/minute
Specimen A
-----
select l.user_id,l.request_timestamp,
#sessionnum :=
if((#curuser = user_id and TIME_TO_SEC(TIMEDIFF(request_timestamp,#theDt))>1800),#sessionnum + 1,
if(#curuser <> user_id,1,#sessionnum)) as sessionnum,
#curuser := user_id as v_curuser,
#theDt:=request_timestamp as v_theDt
from log l cross join
(select #curuser := '', #sessionnum := 0,#theDt:='') gibberish
order by l.user_id,l.request_timestamp
+---------+---------------------+------------+-----------+---------------------+
| user_id | request_timestamp | sessionnum | v_curuser | v_theDt |
+---------+---------------------+------------+-----------+---------------------+
| 1 | 2014-10-26 10:51:18 | 1 | 1 | 2014-10-26 10:51:18 |
| 1 | 2014-10-26 10:52:20 | 1 | 1 | 2014-10-26 10:52:20 |
| 1 | 2014-10-26 11:15:03 | 1 | 1 | 2014-10-26 11:15:03 |
| 1 | 2014-10-26 11:39:18 | 1 | 1 | 2014-10-26 11:39:18 |
| 1 | 2014-10-26 15:01:18 | 2 | 1 | 2014-10-26 15:01:18 |
| 1 | 2014-10-26 15:01:21 | 2 | 1 | 2014-10-26 15:01:21 |
| 1 | 2014-10-27 21:22:19 | 3 | 1 | 2014-10-27 21:22:19 |
| 2 | 2014-10-15 12:19:01 | 1 | 2 | 2014-10-15 12:19:01 |
| 2 | 2014-10-15 12:19:12 | 1 | 2 | 2014-10-15 12:19:12 |
| 2 | 2014-10-15 12:19:45 | 1 | 2 | 2014-10-15 12:19:45 |
| 2 | 2014-10-15 12:20:03 | 1 | 2 | 2014-10-15 12:20:03 |
| 2 | 2014-10-17 14:55:13 | 2 | 2 | 2014-10-17 14:55:13 |
| 2 | 2014-10-17 14:55:19 | 2 | 2 | 2014-10-17 14:55:19 |
| 2 | 2014-10-17 14:55:22 | 2 | 2 | 2014-10-17 14:55:22 |
+---------+---------------------+------------+-----------+---------------------+
Then we are done if you want. But for pretty printing, can wrap Specimen A inside of another:
select user_id,request_timestamp,sessionnum
from
( select l.user_id,l.request_timestamp,
#sessionnum :=
if((#curuser = user_id and TIME_TO_SEC(TIMEDIFF(request_timestamp,#theDt))>1800),#sessionnum + 1,
if(#curuser <> user_id,1,#sessionnum)) as sessionnum,
#curuser := user_id as v_curuser,
#theDt:=request_timestamp as v_theDt
from log l cross join
(select #curuser := '', #sessionnum := 0,#theDt:='') gibberish
order by l.user_id,l.request_timestamp
) SpecimenA
order by user_id,sessionnum
+---------+---------------------+------------+
| user_id | request_timestamp | sessionnum |
+---------+---------------------+------------+
| 1 | 2014-10-26 10:51:18 | 1 |
| 1 | 2014-10-26 10:52:20 | 1 |
| 1 | 2014-10-26 11:15:03 | 1 |
| 1 | 2014-10-26 11:39:18 | 1 |
| 1 | 2014-10-26 15:01:18 | 2 |
| 1 | 2014-10-26 15:01:21 | 2 |
| 1 | 2014-10-27 21:22:19 | 3 |
| 2 | 2014-10-15 12:19:01 | 1 |
| 2 | 2014-10-15 12:19:12 | 1 |
| 2 | 2014-10-15 12:19:45 | 1 |
| 2 | 2014-10-15 12:20:03 | 1 |
| 2 | 2014-10-17 14:55:13 | 2 |
| 2 | 2014-10-17 14:55:19 | 2 |
| 2 | 2014-10-17 14:55:22 | 2 |
+---------+---------------------+------------+
14 rows in set (0.02 sec)
Note the OP's definition of a session. It is one of inactivity, not duration.
Try this:
SELECT user_id,
count(*) as request_count,
min(request_timestamp) as session_start,
max(request_timestamp) as session_end,
timestampdiff(
SECOND,
min(request_timestamp),
max(request_timestamp)
) as session_duration
FROM `log`
GROUP BY user_id
APPENDED
Now with the valued answer of #drew you can get the exactly proposed table2:
Take my output table and insert his code inside the brackets.
SELECT user_id,
sessionnum as `session`,
count(*) as request_count,
min(request_timestamp) as session_start,
max(request_timestamp) as session_end,
timestampdiff(
SECOND,
min(request_timestamp),
max(request_timestamp)
) as session_duration
FROM (put code of drew here) ttt
GROUP BY user_id, sessionnum
However
I am still thinking that you'd better set the session number in a separate field by inserting trigger fired from the table(s) with observed activity to prevent heavy load of the DB in the future when the log becomes too large.
Stop using reserved words and MySQL functions' names for aliases of your table (column) names (ex. log, session in your sample).
Related
I have a MySQL database with a table like:
CREATE TABLE example (Batch_Num int, Time_Stamp datetime);
INSERT INTO example VALUES
(1, '2020-12-10 16:37:43'),
(1, '2020-12-11 09:47:31'),
(1, '2020-12-11 14:02:17'),
(1, '2020-12-11 15:28:02'),
(2, '2020-12-12 15:08:52'),
(2, '2020-12-14 10:38:02'),
(2, '2020-12-14 16:22:35'),
(2, '2020-12-15 08:44:13'),
(3, '2020-12-16 11:38:05'),
(3, '2020-12-17 10:19:13'),
(3, '2020-12-17 14:45:28');
+-----------+-----------------------+
| Batch_Num | Time_Stamp |
+-----------+-----------------------+
| 1 | '2020-12-10 16:37:43' |
| 1 | '2020-12-11 09:47:31' |
| 1 | '2020-12-11 14:02:17' |
| 1 | '2020-12-11 15:28:02' |
| 2 | '2020-12-12 15:08:52' |
| 2 | '2020-12-14 10:38:02' |
| 2 | '2020-12-14 16:22:35' |
| 2 | '2020-12-15 08:44:13' |
| 3 | '2020-12-16 11:38:05' |
| 3 | '2020-12-17 10:19:13' |
| 3 | '2020-12-17 14:45:28' |
+-----------+-----------------------+
I would like to select from this table the first and last timestamp for each value of each Batch_Number. I would like the table to look like:
+-----------+-----------------------+-----------------------+
| Batch_Num | Beginning_Time_Stamp | End_Time_Stamp |
+-----------+-----------------------+-----------------------+
| 1 | '2020-12-10 16:37:43' | '2020-12-11 15:28:02' |
| 2 | '2020-12-12 15:08:52' | '2020-12-15 08:44:13' |
| 3 | '2020-12-16 11:38:05' | '2020-12-17 14:45:28' |
+-----------+-----------------------+-----------------------+
I am not sure how to select both, when the previous Batch_Num is different from the curent one, and also when the next one is different.
A basic GROUP BY query should work here:
SELECT
Batch_Num,
MIN(Time_Stamp) AS Beginning_Time_Stamp,
MAX(Time_Stamp) AS End_Time_Stamp
FROM example
GROUP BY
Batch_Num
ORDER BY
Batch_Num;
Demo
If the same batch number might appear in different series, then aggrgaation alone cannot solve the problem. You would typically approach this with some gaps-and-island technique; here, a simple approach uses the difference between row numbers to identify groups of adjacent records (islands):
select batch_num,
min(time_stamp) as start_time_stamp,
max(time_stamp) as end_time_stamp,
count(*) as cnt
from (
select e.*,
row_number() over(order by time_stamp) as rn1,
row_number() over(partition by batch_num order by time_stamp) as rn2
from example e
) t
group by batch_num, rn1 - rn2
order by start_time_stamp
Here is a demo. I added a new occurence of batch 1 at the end of the dataset:
batch_num | start_time_stamp | end_time_stamp | cnt
--------: | :------------------ | :------------------ | --:
1 | 2020-12-10 16:37:43 | 2020-12-11 15:28:02 | 4
2 | 2020-12-12 15:08:52 | 2020-12-15 08:44:13 | 4
3 | 2020-12-16 11:38:05 | 2020-12-17 14:45:28 | 3
1 | 2020-12-18 14:02:17 | 2020-12-18 15:28:02 | 2
I am trying to use partition by & row_number() to count consecutive duplicate values for a given date range.Essentially its attempting to capture "streaks" If there is a break in the streak the count should start over when the value occurs again.
To reproduce these results here is the code:
CREATE TABLE partion_test (
daily DATE,
response_short_name VARCHAR(10)
);
INSERT INTO `partion_test` (`daily`, `response_short_name`) VALUES
('2020-09-21', 'A'),
('2020-09-25', 'A'),
('2020-09-26', 'A'),
('2020-09-27', 'A'),
('2020-09-28', 'A'),
('2020-09-22', 'B'),
('2020-09-20', 'C'),
('2020-09-23', 'C'),
('2020-09-24', 'C');
SELECT
daily,
response_short_name
,row_number() over (partition by response_short_name order by daily) as seqnum
FROM (
select
daily,
response_short_name
FROM partion_test
order by daily limit 1000
) A;
HERE IS THE CURRENT OUTPUT
| daily | response_short_name | seqnum | |
+------------+---------------------+--------+--+
| 2020-09-21 | A | 1 | |
| 2020-09-25 | A | 2 | |
| 2020-09-26 | A | 3 | |
| 2020-09-27 | A | 4 | |
| 2020-09-28 | A | 5 | |
| 2020-09-22 | B | 1 | |
| 2020-09-20 | C | 1 | |
| 2020-09-23 | C | 2 | |
| 2020-09-24 | C | 3 | |
+------------+---------------------+--------+--+
HERE IS THE DESIRED OUTPOUT
+------------+---------------------+--------+--+
| daily | response_short_name | seqnum | |
+------------+---------------------+--------+--+
| 2020-09-20 | C | 1 | |
| 2020-09-21 | A | 1 | |
| 2020-09-22 | B | 1 | |
| 2020-09-23 | C | 1 | |
| 2020-09-24 | C | 2 | |
| 2020-09-25 | A | 1 | |
| 2020-09-26 | A | 2 | |
| 2020-09-27 | A | 3 | |
| 2020-09-28 | A | 4 | |
+------------+---------------------+--------+--+
Ive been scratching at my brain for a while on this. Any help would be appreciated
You can do:
select *,
row_number() over(partition by grp order by daily) as seqnum
from (
select *,
sum(inc) over(order by daily) as grp
from (
select *,
case when lag(response_short_name) over(order by daily) = response_short_name
then 0 else 1 end as inc
from partion_test
order by daily
) x
) y
order by daily
Result:
daily response_short_name inc grp seqnum
----------- -------------------- ---- ---- ------
2020-09-20 C 1 1 1
2020-09-21 A 1 2 1
2020-09-22 B 1 3 1
2020-09-23 C 1 4 1
2020-09-24 C 0 4 2
2020-09-25 A 1 5 1
2020-09-26 A 0 5 2
2020-09-27 A 0 5 3
2020-09-28 A 0 5 4
See running example at DB Fiddle:
Your data doesn't fit your result, so it is quite diffcult t achieve your result
CREATE TABLE partion_test (
daily DATE,
response_short_name VARCHAR(10)
);
INSERT INTO `partion_test` (`daily`, `response_short_name`) VALUES
('2020-09-21', 'A'),
('2020-09-25', 'A'),
('2020-09-26', 'A'),
('2020-09-27', 'A'),
('2020-09-28', 'A'),
('2020-09-22', 'B'),
('2020-09-20', 'C'),
('2020-09-23', 'C'),
('2020-09-24', 'C');
select `daily`,`response_short_name`,
row_number() over (partition by `response_short_name`, grp order by `daily`) as row_num
from (select t.*,
(row_number() over (order by `daily`) -
row_number() over (partition by `response_short_name` order by `daily`)
) as grp
from partion_test t
) t
ORDER BY `daily`
daily | response_short_name | row_num
:--------- | :------------------ | ------:
2020-09-20 | C | 1
2020-09-21 | A | 1
2020-09-22 | B | 1
2020-09-23 | C | 1
2020-09-24 | C | 2
2020-09-25 | A | 1
2020-09-26 | A | 2
2020-09-27 | A | 3
2020-09-28 | A | 4
db<>fiddle here
I'm having trouble making this query, can I get some help?
I have a table named measurements that looks like this:
+----+----------+-------+------+
| id | cost | month | year |
+----+----------+-------+------+
| 1 | 6860.52 | 5 | 2018 |
| 1 | 11993.52 | 6 | 2018 |
| 1 | 3823.2 | 7 | 2018 |
| 1 | 3557.7 | 8 | 2018 |
| 1 | 3355.92 | 9 | 2018 |
| 1 | 357.54 | 10 | 2018 |
+----+----------+-------+------+
and a table named payment
+------------+---------------+-----------------+
| id | period | payment |
+------------+---------------+-----------------+
| 1 | 2018-05-01 | 0 |
| 1 | 2018-06-01 | 0 |
| 1 | 2018-06-01 | 34327 |
| 1 | 2018-07-01 | 100 |
| 1 | 2018-07-01 | 500 |
| 1 | 2018-07-01 | 400 |
| 1 | 2018-08-01 | 0 |
+------------+---------------+-----------------+
I'm in trouble trying to make a select stament that returns this:
+------------+---------------+----------------+-----------------+
| id | period | date | payment |
+------------+---------------+----------------+-----------------+
| 1 | 2018-05-01 | 2018-05-01 | 0 |
| 1 | 2018-06-01 | 2018-06-01 | 34327 |
| 1 | 2018-07-01 | 2018-07-01 | 1000 |
| 1 | 2018-08-01 | 2018-08-01 | 0 |
| 1 | 2018-09-01 | NULL | 0 |
| 1 | 2018-10-01 | NULL | 0 |
+------------+---------------+----------------+-----------------+
date is from concat(year,'-',month,'-',1)
Thank you
Schema:
CREATE TABLE measurements (id INT, cost FLOAT, month INT, year INT);
INSERT INTO measurements VALUES (1, 6860.52, 5, 2018),
(1, 11993.52, 6, 2018), (1, 3823.2, 7, 2018),
(1, 3557.7, 8, 2018), (1, 3355.92, 9, 2018), (1, 357.54, 10, 2018);
CREATE TABLE payment (id INT, period DATE, payment INT);
INSERT INTO payment VALUES (1, '2018-05-01', 0),
(1, '2018-06-01', 0),(1, '2018-06-01', 34327 ),(1, '2018-07-01', 100),
(1, '2018-07-01', 500),(1, '2018-07-01', 400), (1, '2018-08-01', 0);
Are you searching for this?
select measurements.id,
cast(concat(measurements.year, '-', measurements.month, '-01') as date) as period,
payment.period as date, sum(payment) payment
from measurements
left join payment on measurements.id = payment.id and cast(concat(measurements.year, '-', measurements.month, '-01') as date) = payment.period
group by measurements.id, measurements.year, measurements.month, payment.period
order by measurements.year, measurements.month;
You can try below using left join
select id,str_to_date(concat(year,'-',month,'-',1),'%Y-%m-%d') as period,b.period as `date`,sum(payment) as payment
from measurements a left join payment b
on a.id=b.id and str_to_date(concat(year,'-',month,'-',1),'%Y-%m-%d')=b.period
group by str_to_date(concat(year,'-',month,'-',1),'%Y-%m-%d')
I have a table like this:
// mytable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 10 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 5 | jack | 1 | 5 |
| 6 | jack | 1 | 10 |
| 7 | bert | 4 | 2 |
| 8 | peter | 2 | 10 |
| 9 | bert | 4 | 5 |
+----+--------+-------+-------+
Now I want to sum the numbers of value where both name and key are identical. So, I want this output:
// mynewtable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 25 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
+----+--------+-------+-------+
Is it possible to I do that?
Edit: How can I do that for insert?
// mytable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 25 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
+----+--------+-------+-------+
Inserting these rows:
+----+--------+-------+-------+
| 10 | jack | 1 | 5 |
+----+--------+-------+-------+
+----+--------+-------+-------+
| 11 | bert | 1 | 2 |
+----+--------+-------+-------+
What I want: (output)
// mynewtable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 30 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
| 11 | bert | 1 | 2 |
+----+--------+-------+-------+
You have to group by more columns.
select name, key, sum(value) from mytable group by name, key;
Group by name, key
select name, key, sum(value) as value
from mytable group by name,key
check this
CREATE TABLE #testing_123
([id] int, [name] varchar(5), [key] int, [value] int)
;
INSERT INTO #testing_123
([id], [name], [key], [value])
VALUES
(1, 'jack', 1, 10),
(2, 'peter', 1, 5),
(3, 'jack', 2, 5),
(4, 'ali', 1, 2),
(5, 'jack', 1, 5),
(6, 'jack', 1, 10),
(7, 'bert', 4, 2),
(8, 'peter', 2, 10),
(9, 'bert', 4, 5)
;
query used was
select min(id) id ,name,[key],sum(value) value from #testing_123 group by name,[key] order by 1
output after insert
For the first part (to get the id column in the way requested), you could work along:
INSERT INTO mynewtable
(id, name, `key`, `value`)
SELECT
MIN(id), name, `key`, SUM(`value`)
FROM mytable
GROUP BY name, `key`
;
Now, provided mynewtable is defined with a unique index on name and key like
CREATE TABLE mynewtable
(id INT, name VARCHAR(5), `key` INT, `value` INT, UNIQUE (name, `key`));
you'd get the requested result with
INSERT INTO mynewtable
(id, name, `key`, `value`)
VALUES
(10, 'jack', 1, 5),
(11, 'bert', 1, 2)
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)
;
Beware:
It requires the unique index on name and key to work.
It might not work correctly, if there are other unique indexes and/or a primary key on the same table as well.
NB:
Please try to avoid the use of reserved words such as value and key for, e.g., column names.
I want my tables to output something like this
---------------------------------------------------------------------------------------------
| date | location | time | delegate 1 | delegate 2 |
|--------------------------------------------------------------------------------------------
| 2015-12-07 | Table 1 | 9:00 | first_name_4 last_name_4 | first_name_5 last_name_5 |
|--------------------------------------------------------------------------------------------
| | 9:30 | first_name_4 last_name_4 | first_name_6 last_name_6 |
|--------------------------------------------------------------------------------------------
| | 9:30 | first_name_3 last_name_3 | first_name_7 last_name_7 |
|--------------------------------------------------------------------------------------------
| | 9:00 | first_name_3 last_name_3 | first_name_7 last_name_7 |
|--------------------------------------------------------------------------------------------
Here are the tables on my db
meetings table
-------------------------------------------------------------------------------------------------
| id | date_id | time_id | location_id | delegate_id_1 | delegate_id_2 | status |
|------------------------------------------------------------------------------------------------
| 1 | 1 | 1 | 1 | 4 | 5 | A |
|------------------------------------------------------------------------------------------------
| 2 | 1 | 2 | 1 | 4 | 6 | A |
|------------------------------------------------------------------------------------------------
| 3 | 1 | 1 | 1 | 2 | 6 | P |
|------------------------------------------------------------------------------------------------
| 4 | 1 | 2 | 1 | 1 | 3 | A |
|------------------------------------------------------------------------------------------------
| 5 | 1 | 1 | 1 | 1 | 3 | A |
|------------------------------------------------------------------------------------------------
users table
-----------------------------------------
| id | first_name | last_name |
|----------------------------------------
| 1 | first_name_1 | last_name_1 |
|----------------------------------------
| 2 | first_name_2 | last_name_2 |
|----------------------------------------
| 3 | first_name_3 | last_name_3 |
|----------------------------------------
| 4 | first_name_4 | last_name_4 |
|----------------------------------------
| 5 | first_name_5 | last_name_5 |
|----------------------------------------
| 6 | first_name_6 | last_name_6 |
|----------------------------------------
locations table
-----------------------------
| id | location_name |
|----------------------------
| 1 | Table 1 |
|----------------------------
time table
-------------------------
| id | meeting_time |
|------------------------
| 1 | 9:00:00 |
|------------------------
| 1 | 9:30:00 |
|------------------------
dates table
-------------------------
| id | meeting_date |
|------------------------
| 1 | 2015-12-07 |
|------------------------
| 2 | 2015-12-08 |
|------------------------
| 3 | 2015-12-09 |
|------------------------
My initial query goes like this
-- $query_date
SELECT meeting_date
FROM dates
WHERE meeting_date = '2015-12-07'
-- $query_location
SELECT location_name.location
from location
LEFT JOIN meetings
ON meetings.location_id=location.id
LEFT JOIN date
ON meetings.date_id=date.id
WHERE meeting_date.dates = '2015-12-07'
Now, here's the part where I got it wrong.
-- $query_final
SELECT meeting_time.time, delegate1.first_name AS first_name_1,
delegate1.last_name AS last_name_1, delegate2.first_name AS first_name_2,
delegate2.last_name AS last_name_2
FROM meetings
INNER JOIN users delegate1
ON meetings.delegate_id_1=users.id
LEFT JOIN users delegate2
ON meetings.delegate_id_2=users.id
WHERE meetings.status='A'
The results on my last query give me unexpected results since the results show more entries than my meetings table.
I know the queries I made are costly but I don't know how to make a more optimized query. I don't even know if it's possible to get the results into a single query only. Any help well do. Thanks.
You can bring back everything with a single query with the right JOIN.
Be Careful, when you use column name on SQL, the syntax is TABLE.COLUMN_NAME, it seem you mistake on the order quit often...
I changed some table name as you sometime use an s at the end and sometime no.
As time and date are SQL keyword, it's better with s everywhere
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE meetings (`id` int, `date_id` int, `time_id` int, `location_id` int, `delegate_id_1` int, `delegate_id_2` int, `status` varchar(1));
INSERT INTO meetings (`id`, `date_id`, `time_id`, `location_id`, `delegate_id_1`, `delegate_id_2`, `status`)
VALUES (1, 1, 1, 1, 4, 5, 'A'),
(2, 1, 2, 1, 4, 6, 'A'),
(3, 1, 1, 1, 2, 6, 'P'),
(4, 1, 2, 1, 1, 3, 'A'),
(5, 1, 1, 1, 1, 3, 'A');
CREATE TABLE users (`id` int, `first_name` varchar(12), `last_name` varchar(11));
INSERT INTO users (`id`, `first_name`, `last_name`)
VALUES (1, 'first_name_1', 'last_name_1'),
(2, 'first_name_2', 'last_name_2'),
(3, 'first_name_3', 'last_name_3'),
(4, 'first_name_4', 'last_name_4'),
(5, 'first_name_5', 'last_name_5'),
(6, 'first_name_6', 'last_name_6');
CREATE TABLE locations (`id` int, `location_name` varchar(7));
INSERT INTO locations (`id`, `location_name`)
VALUES (1, 'Table 1');
CREATE TABLE times (`id` int, `meeting_time` varchar(7));
INSERT INTO times (`id`, `meeting_time`)
VALUES (1, '9:00:00'),
(2, '9:30:00') ;
CREATE TABLE dates (`id` int, `meeting_date` varchar(10)) ;
INSERT INTO dates (`id`, `meeting_date`)
VALUES (1, '2015-12-07'),
(2, '2015-12-08'),
(3, '2015-12-09') ;
Query 1:
-- $query_final
SELECT locations.location_name,
`times`.meeting_time,
delegate1.first_name AS first_name_1,
delegate1.last_name AS last_name_1,
delegate2.first_name AS first_name_2,
delegate2.last_name AS last_name_2
FROM meetings
LEFT JOIN locations
ON meetings.location_id=locations.id
LEFT JOIN dates
ON meetings.date_id=`dates`.id
LEFT JOIN times
ON meetings.time_id=`times`.id
INNER JOIN users delegate1
ON meetings.delegate_id_1 = delegate1.id
LEFT JOIN users delegate2
ON meetings.delegate_id_2 = delegate2.id
WHERE
meetings.status = 'A'
AND dates.meeting_date = '2015-12-07'
Results:
| location_name | meeting_time | first_name | last_name | first_name | last_name |
|---------------|--------------|--------------|-------------|--------------|-------------|
| Table 1 | 9:00:00 | first_name_1 | last_name_1 | first_name_3 | last_name_3 |
| Table 1 | 9:30:00 | first_name_1 | last_name_1 | first_name_3 | last_name_3 |
| Table 1 | 9:00:00 | first_name_4 | last_name_4 | first_name_5 | last_name_5 |
| Table 1 | 9:30:00 | first_name_4 | last_name_4 | first_name_6 | last_name_6 |