Help with MySQL join 3 Tables - mysql

I am working on a registration system that uses the following tables:
Person (name etc.), Course (course date), Registration (association table pid, cid)
Person
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | text | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
Example Data:
select * from person;
+-----+--------+
| id | name |
+-----+--------+
| 101 | Graham |
| 102 | Lisa |
| 103 | John |
+-----+--------+
Course
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | text | YES | | NULL | |
| date | date | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
select * from course;
+----+---------+------------+
| id | name | date |
+----+---------+------------+
| 1 | Hip Hop | 2011-06-08 |
| 2 | Dancing | 2006-06-23 |
| 3 | Running | 2007-07-08 |
+----+---------+------------+
Registration
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| pid | int(11) | YES | | NULL | |
| cid | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
select * from registration;
+----+------+------+
| id | pid | cid |
+----+------+------+
| 1 | 101 | 1 |
| 2 | 101 | 2 |
| 3 | 103 | 2 |
+----+------+------+
I would like to find person(s) that have no registration records within the past two years. I am attempting to join the tables based on date calculation but it does not seem to work this way. Is this possible with mysql or is my approach of trying this with one query wrong?
query I have come up with:
select * from
(person left join registration on person.id = registration.pid)
left join course on course.id = registration.cid
AND DATE_FORMAT(`course`.`date`, "%m.%Y") > DATE_FORMAT( DATE_SUB(NOW(), INTERVAL 2 YEAR),"%m.%Y")
WHERE
registration.id IS NULL;
+-----+------+------+------+------+------+------+------+
| id | name | id | pid | cid | id | name | date |
+-----+------+------+------+------+------+------+------+
| 102 | Lisa | NULL | NULL | NULL | NULL | NULL | NULL |
+-----+------+------+------+------+------+------+------+
It should list person 102 and 103 since both registrations are older than 2 years and no other records of newer course dates can be found...

Give this a shot, using a NOT EXISTS clause:
select p.* from person p
where not exists (select 1 from person px
join registration rx on px.id = rx.pid
join course cx on rx.cid = cx.id
where px.id = p.id
and cx.date > DATE_SUB(NOW(), INTERVAL 2 YEAR))

Related

Mysql mapping two table

How to mapping two table ?
table tableA:
+------------------+-----------------------+------+-----+---------------------+-------------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-----------------------+------+-----+---------------------+-------------------------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| price | decimal(8,2) | NO | | NULL | |
+------------------+-----------------------+------+-----+---------------------+-------------------------------+
+------+------------+
| id | name | price |
+------+------------+
12 | foo | 0.12 |
2 | barr | 0.20 |
+------+------------+
table tableB:
+------------+-----------------------+------+-----+---------------------+-------------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-----------------------+------+-----+---------------------+-------------------------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| user_id | int(10) | NO | | NULL | |
| service_id | int(10) | NO | | NULL | |
| price | decimal(8,2) | NO | | NULL | |
+------------+-----------------------+------+-----+---------------------+-------------------------------+
+------------+------------+
| user_id | service_id | price |
+------------+------------+
| 2 | 12 | 0.01 |
+------------+------------+
When query to get of user mapping. Also like "SELECT price FROM tableA" need returns tableB column value.
Example of result:
+------+------------+
| id | name | price |
+------+------------+
12 | foo | 0.01 |
+------+------------+
What do you really mean by mapping two tables? There are three main mapping methods.
Insert
Update
Delete
I think you can get more idea of visiting these sites.
(http://www.mysqltutorial.org/compare-two-tables-to-find-unmatched-records-mysql.aspx)
(https://help.10web.io/hc/en-us/articles/360016083011-Settings-MySQL-Mapping)
Based on "Example Result" you are trying to link TableA with TableB with id and service_id. In that case, you can achieve the result by running this query
Select ta.id,ta.name,tb.price
from TableA ta,TableB tb Where
ta.id = tb.service_id;
The above query provides the relation for the tables.

Dsictint bi-directional relation

I have table that describes realtionships between other tables in database. Every user can have any file, and every file can have any user.
If I get one files' relations and I don't have this file relation to user, but user has relation to that file. I want to see that.
When both have relations to themselves I don't want to see twice records.
As an input I have record type and record id. How to achieve that?
Closure table:
+--------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| record_id | int(11) | NO | | NULL | |
| record_type | varchar(200) | NO | | NULL | |
| second_record_id | int(11) | NO | | NULL | |
| second_record_type | varchar(200) | NO | | NULL | |
+--------------------+--------------+------+-----+---------+----------------+
Sample data:
+----+-----------+-------------+------------------+--------------------+
| id | record_id | record_type | second_record_id | second_record_type |
+----+-----------+-------------+------------------+--------------------+
| 1 | 1 | files | 1 | users |
| 2 | 2 | users | 1 | files |
| 3 | 3 | users | 1 | files |
| 4 | 2 | files | 1 | users |
| 5 | 1 | users | 1 | files |
| 6 | 1 | files | 3 | users |
+----+-----------+-------------+------------------+--------------------+
I've tried
SELECT * FROM closure
WHERE record_id=1 OR second_record_id = 1
AND record_type="files" OR second_record_type="files"
GROUP BY "files"
HAVING record_id=1 OR second_record_id=1
but it gets me one relation:
+----+-----------+-------------+------------------+--------------------+
| id | record_id | record_type | second_record_id | second_record_type |
+----+-----------+-------------+------------------+--------------------+
| 1 | 1 | files | 1 | users |
+----+-----------+-------------+------------------+--------------------+
My desired result would be:
+----+-----------+-------------+------------------+--------------------+
| id | record_id | record_type | second_record_id | second_record_type |
+----+-----------+-------------+------------------+--------------------+
| 1 | 1 | files | 1 | users |
| 2 | 2 | users | 1 | files |
| 6 | 1 | files | 3 | users |
+----+-----------+-------------+------------------+--------------------+
Sql fiddle
EDIT
I've dropped id column finally.
I think you just want to compare both the "1" and the "files" at the same type, for each record type. This should produce your desired result:
SELECT c.*
FROM closure c
WHERE (record_id = 1 and record_type = 'files') OR
(second_record_id = 1 and second_record_type = 'files');
You don't have aggregation function so the group by and the having clause are unuseful if you wondt distinct add distinct clause (but the use of id don't permit a proper work)
SELECT *
FROM closure
WHERE ( record_id=1 OR second_record_id = 1 )
AND (record_type="files" OR second_record_type="files" )
or
SELECT distinct record_id, record_type, second_record_id, second_record_type
FROM closure
WHERE ( record_id=1 OR second_record_id = 1 )
AND ( record_type="files" OR second_record_type="files" )

COUNT, Minimum Value per course without subquery

Can anyone help me find the minimum student action per course? Listed like this:
+-------------+--------------------------+
| Course | Lowest Action |
+-------------+--------------------------+
| Maths Y1 | |
| English C | |
| Science Y1 | |
for all users, even if they are not in the log table, without a subquery? My thanks to #luckylwk for assistance with my initial query. I have a solution with a subquery but want to put this into a variable for a much large query.
SELECT
COUNT(tbl_log.action)
lastname,
c.fullname,
FROM tbl_log
JOIN tbl_user ON tbl_log.userid = tbl_user.id
JOIN tbl_course ON tbl_log.course = tbl_course.id
GROUP BY tbl_log.userid, tbl_log.course
LOG TABLE
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | | NO | PRI | NULL | auto_increment |
| time | | NO | | NULL | |
| userid | | NO | | NULL | |
| course | | NO | | NULL | |
| action | | NO | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
USER Table
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| id | | NO | PRI | NULL | auto_increment |
| username | | NO | | NULL | |
| userpassword | | NO | | NULL | |
| lastname | | NO | | NULL | |
| firstname | | NO | | NULL | |
+--------------+---------------------+------+-----+---------+----------------+
COURSE table
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| id | | NO | PRI | NULL | auto_increment |
| category | | NO | | NULL | |
| fullname | | NO | | NULL | |
| shortname | | NO | | NULL | |
+--------------+---------------------+------+-----+---------+----------------+
I link the users together via the enrolment and context tables.
Try:
SELECT
tbl_course.course_name,
MIN(tbl_log.action) as Lowest_Action
FROM tbl_log
JOIN tbl_user ON tbl_log.userid = tbl_user.id
JOIN tbl_course ON tbl_log.course = tbl_course.id
GROUP BY tbl_course.course_name
See Fiddle Demo

MySQL count 2 columns in a row and join with another query

I have a table visits like this:
+--------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| vis_id | int(11) | NO | | NULL | |
| unit | int(11) | NO | | NULL | |
| time_in | timestamp | NO | | CURRENT_TIMESTAMP | |
| time_out | timestamp | NO | | 0000-00-00 00:00:00 | |
| in_username | varchar(16) | NO | | NULL | |
| out_username | varchar(16) | NO | | NULL | |
+--------------+-------------+------+-----+---------------------+----------------+
and a table users like this:
+------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| fname | varchar(32) | NO | | NULL | |
| lname | varchar(32) | NO | | NULL | |
| date_added | timestamp | NO | | CURRENT_TIMESTAMP | |
| username | varchar(16) | NO | | NULL | |
| password | varchar(40) | NO | | NULL | |
| auth_level | int(1) | NO | | 1 | |
| last_login | timestamp | NO | | 0000-00-00 00:00:00 | |
+------------+-------------+------+-----+---------------------+----------------+
I want to be able to count how many times each user is in in_username AND out_username... The query I was using before looks like this:
select count(*) as "count", u.fname as "fname"
from visits v
inner join users as u on u.username = v.in_username
group by u.username order by u.fname
But that only returns how many in_username's there are... I'd like to have both in the same query if possible, so I could get results like this:
+----------+-----------+----------+
| count_in | count_out | fname |
+----------+-----------+----------+
| 118 | 224 | Bo |
| 27 | 64 | James |
| 147 | 138 | Jeremy |
| 23 | 37 | Jim |
| 182 | 172 | Robert |
| 120 | 158 | Tom |
+----------+-----------+----------+
Where count_in is how many times their username appears in visits.in_username, and count_out is how many times their username appears in visits.out_username
Everything I've tried with UNION seems to add the counts together, or removes rows for some reason. Any ideas?
Do a subquery to get each total, combine them with UNION, and then merge them with SUM().
SELECT SUM(count_in) count_in, SUM(count_out) count_out, fname
FROM (SELECT COUNT(*) count_in, 0 count_out, in_username fname
FROM visits v
GROUP BY fname
UNION
SELECT 0 count_in, COUNT(*) count_out, out_username fname
FROM visits v
GROUP BY fname) combined

Hibernate select relevent data in one query

I am new to Hibernate.
This is a User table
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(16) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| sex | char(1) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
This is my sample data
+----+-------+------+------+
| id | name | age | sex |
+----+-------+------+------+
| 1 | Amit | 20 | M |
| 2 | Sumit | 21 | M |
| 3 | Mohan | 22 | M |
| 4 | Ram | 26 | M |
| 5 | John | 22 | M |
| 6 | Sita | 19 | F |
+----+-------+------+------+
These are my queries:
select id from User where name="Amit" and age=20;
select id from User where name="Ram" and age=26;
select id from User where name="Mohan" and age=22;
select id from User where name="Sita" and age=19;
I can do this in hibernate by running 4 queries.
Is there any way by which I can do this in just one query?
Please tell the same can be done in mysql too.
Please help. Any clue, link or reference will be appreciable.
Thank you.
you can do this
select id , name ,age , sex from User
where (name,age) IN (('Amit','20'),('Ram', '26'),('Mohan', '22'),('Sita', '19'));
DEMO HERE
In sql ...
select name, id from User where ( name="Amit" and age=20)
or ( name="Ram" and age=26 )
or ( name="Mohan" and age=22 )
or ( name="Sita" and age=19 )