Complex MySQL Join with 3 tables and many2many relations - mysql

I have 3 tables person, account and subscription. Account belongs to Person as one to many and Account and Subscription are many to many.I need a sql which can select data from three tables.-
Person Tables
+----------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(128) | NO | | NULL | |
| password | varchar(128) | NO | | NULL | |
| account_id | int(11) | NO | | NULL | |
+----------------------------+---------------+------+---------------+----------------+
Account table
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| yearly_renew | tinyint(1) | NO | | NULL | |
| date_joined | date | NO | | NULL | |
| last_renewed | datetime | YES | | NULL | |
| signup | tinyint(1) | NO | | NULL | |
| reason | varchar(100) | YES | | NULL | |
| yearly_total | int(11) | YES | | NULL | |
| total | int(11) | YES | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
Account-Subscription table
+-----------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| account_id | int(11) | NO | MUL | NULL | |
| subscription_id | int(11) | NO | MUL | NULL | |
+-----------------+---------+------+-----+---------+----------------+
Subscription table
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subscription_type | varchar(150) | YES | | NULL | |
| hold | tinyint(1) | NO | | NULL | |
| start_date | date | YES | | NULL | |
| end_date | date | YES | | NULL | |
| amount_paid | double | YES | | NULL | |
| date_paid | date | YES | | NULL | |
| transaction_id | int(11) | YES | | NULL | |
| free | tinyint(1) | NO | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
Expecting output in a single query -
OUTPUT
+-----------+------------+--------------+
| person.id | account.id | subscription.id |
+-----------+------------+--------------+
| 10 | 11 | 20 |
| 15 | 32 | 45 |
| 23 | 43 | null |
+--------+---------+-----------------+

try this. it may works properly...
SELECT p.Id AS person.id
,p.account_id AS account.id
,acsub.subscription_id as subscription.id
FROM Person AS p
LEFT JOIN Account-Subscription AS acsub ON p.account_id=acsub.account_id

SELECT p.Id AS person.id
,p.account_id AS account.id
,acsub.subscription_id as subscription.id
FROM Person AS p
INNER JOIN
Account-Subscription AS acsub ON p.account_id=acsub.account_id

Related

How to add a date selection in sql

I want to be able to select classes that are starting on or after the next two hours up until the end of tomorrow's date but I am not sure of how to do this.
My current sql is below, I have only been able to select classes that are after today's date and after the current time. I want to be able to only return classes that start two hours after now up until the end of tomorrows date.
I am able to pass the current date and current time into my node.js function that will construct the sql statement. Also, I have access to moment.js library if I need to use this I could.
Any help would be appreciated.
SELECT DISTINCT b.name
, a.time
FROM class a
Inner join (SELECT class_id, count(clientid)
FROM bookings
GROUP BY class_id
HAVING count(clientid) < 10) as openClasses on
a.class_id = openClasses.class_id
JOIN class_detail b
ON a.class_id = b.id
JOIN branch c
ON a.branch_id = c.id
WHERE c.level <= ( SELECT d.level
FROM client d
WHERE d.facebook_id = 'xxxxxx'
)
AND a.date = '2016-08-17'
AND a.time >= '13.00.00';
My tables are as follows:
BOOKINGS
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | bigint(20) | NO | PRI | NULL | |
| CLIENT_ID | int(11) | NO | | NULL | |
| CLASS_ID | int(11) | NO | | NULL | |
| STATUS | varchar(10) | NO | | NULL | |
+-----------+-------------+------+-----+---------+-------+
mysql> show fields from BRANCH;
+---------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+----------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| NAME | char(50) | NO | | NULL | |
| CONTACT_NO | char(50) | YES | | NULL | |
| MAP_IMG_PATH | char(200) | YES | | NULL | |
| ADDRESS | char(200) | YES | | NULL | |
| LEVEL | int(2) | NO | | NULL | |
| LOCATION | int(10) | YES | | NULL | |
| SECTOR_NAME | varchar(45) | YES | | NULL | |
| SECTOR_MAP_IMG_PATH | char(200) | YES | | NULL | |
+---------------------+-------------+------+-----+---------+----------------+
mysql> show fields from CLIENT;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id | int(10) | NO | PRI | NULL | |
| NAME | char(50) | NO | | NULL | |
| DOB | int(8) | NO | | NULL | |
| LOCAL_BRANCH | int(10) | YES | | NULL | |
| FACEBOOK_ID | char(50) | NO | | NULL | |
| START_DATE | int(8) | NO | | NULL | |
| EMAIL | char(50) | YES | | NULL | |
| PIN | int(4) | YES | | NULL | |
| END_DATE | int(8) | NO | | NULL | |
| LEVEL | int(2) | YES | | NULL | |
| TEL | varchar(20) | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+
mysql> show fields from CLASS_DETAIL;
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(10) | NO | PRI | NULL | |
| NAME | char(50) | NO | | NULL | |
| DESCRIPTION | char(200) | NO | | NULL | |
| CATEGORY | varchar(4) | YES | | NULL | |
| ACHIEVE_TYPE | char(200) | YES | | NULL | |
| IMG_M | varchar(200) | YES | | NULL | |
| IMG_F | varchar(200) | YES | | NULL | |
+--------------+--------------+------+-----+---------+-------+
mysql> show fields from CLASS;
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| CLASS_ID | int(10) | YES | | NULL | |
| BRANCH_ID | int(10) | NO | | NULL | |
| DURATION | int(3) | YES | | NULL | |
| DATE | date | NO | | NULL | |
| TIME | time | NO | | NULL | |
| STATUS | char(1) | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
7 rows in set (0.11 sec)

Need a SQL command for these tables

I have the following 2 tables (student and attendance):
mysql> describe student;
+----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+----------------+
| student_id | int(11) | NO | PRI | NULL | auto_increment |
| student_email | varchar(255) | YES | | NULL | |
| student_phone_number | varchar(255) | YES | | NULL | |
| parent_first_name | varchar(255) | NO | | NULL | |
| parent_last_name | varchar(255) | NO | | NULL | |
| parent_email | varchar(255) | NO | | NULL | |
| parent_phone_number | varchar(255) | NO | | NULL | |
| first_name | varchar(255) | NO | | NULL | |
| last_name | varchar(255) | NO | | NULL | |
| days_absent | int(11) | YES | | NULL | |
| days_tardy | int(11) | YES | | NULL | |
| class_id | int(11) | NO | MUL | NULL | |
+----------------------+--------------+------+-----+---------+----------------+
mysql> describe attendance;
+-----------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------+------+-----+---------+-------+
| student_id | int(11) | NO | PRI | NULL | |
| class_id | int(11) | NO | PRI | NULL | |
| attendance_date | date | NO | PRI | NULL | |
| absent | tinyint(1) | YES | | NULL | |
| tardy | tinyint(1) | YES | | NULL | |
| note | text | YES | | NULL | |
+-----------------+------------+------+-----+---------+-------+
I want to check the attendance and email of all the children who are absent or tardy for the day. Is there a SQL statement I can use that can, for example, select the students from attendance with an absent/tardy value = 1, then using that student_id specified in the attendance table, pull all the student info from the student table where attendance.student_id = student.student_id?
just try exists
select student_email,student_phone_number from student std
where exists(
select 1 from attendance atd where std.student_id = atd.student_id
and (atd.absent =1 or atd.tardy =1)
)
just make sure you select all the info from student table and exists all the filter in attendance talbe. the condition is student_id.
Also if you need info from attendance talbe, then use join.

Not getting desired result using join in mysql

I tried left,right,inner join here is my tables
SHOP_OFFER_STATUS
+-----------------------+--------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------------------+----------------+
| MOBILE_NUM | varchar(100) | YES | | NULL | |
| SHOP_ID | varchar(100) | YES | | NULL | |
| OFFER_ID | int(255) | YES | | NULL | |
| OFFER_STATUS | varchar(100) | YES | | NULL | |
| OFFER_GENERATED_ID | int(255) | NO | PRI | NULL | auto_increment |
| OFFER_GENERATED_DATE | timestamp | NO | | CURRENT_TIMESTAMP | |
| OFFER_EXPIRY_DATE | timestamp | NO | | 0000-00-00 00:00:00 | |
| OFFER_CODE | varchar(10) | YES | | NULL | |
| AMOUNT | decimal(9,2) | YES | | NULL | |
| BILL_AMOUNT | decimal(9,2) | YES | | NULL | |
+-----------------------+--------------+------+-----+---------------------+----------------+
TRACK_TRANSACTIONS
+------------------+---------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------+------+-----+-------------------+----------------+
| TRANSACTION_ID | int(255) | NO | PRI | NULL | auto_increment |
| TRANCTION_TYPE | varchar(100) | YES | MUL | NULL | |
| TRANSACTION_DATE | timestamp | NO | | CURRENT_TIMESTAMP | |
| AMOUNT | decimal(10,2) | YES | | NULL | |
| MOBILE_NUM | varchar(15) | YES | | NULL | |
| SHOP_ID | varchar(200) | YES | | NULL | |
+------------------+---------------+------+-----+-------------------+----------------+
i know its my design problem and i have thousands of records(can't rollback or redesign),here how it works when ever person redeems the offer in transaction table shop_id and mobile_num will be added I am trying to get BILL_AMOUNT,TRANSACTION_DATE from this tables...but its giving wrong result...i want to know when(TRANSACTION_DATE ) and what amount he redeemed!
TRANSACTION table have many other transactions like usercreated,commented etc(TRANCTION_TYPE) and offer redemption are around TRANCTION_TYPE='MERCHANT CASHBACK' 100 records if i join this tables more then 50 thousands records comes in :( here is the query!
SELECT COUNT(*)
FROM TRACK_TRANSACTIONS T RIGHT JOIN
SHOP_OFFER_STATUS S
ON T.SHOP_ID=S.SHOP_ID
WHERE T.TRANCTION_TYPE='MERCHANT CASHBACK' AND S.OFFER_STATUS='REDEEMED';
the desired output:100 records where offer redemption happend!

Include null values in SQL query

I have the following four tables in my database:
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+----------------+
| complex_id | int(11) | NO | PRI | NULL | auto_increment |
| complex_name | varchar(45) | NO | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+----------------+
| machine_id | int(11) | NO | PRI | NULL | auto_increment |
| complex_id | int(11) | NO | MUL | NULL | |
| machine_name | varchar(45) | NO | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
+-----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+----------------+
| devices_id | int(11) | NO | PRI | NULL | auto_increment |
| machine_id | int(11) | NO | MUL | NULL | |
| description | varchar(255) | NO | | NULL | |
| location | varchar(255) | YES | | NULL | |
| verification | varchar(255) | YES | | NULL | |
| rack_num | varchar(8) | YES | | NULL | |
| section_num | varchar(8) | YES | | NULL | |
| color_or_number | varchar(16) | YES | | NULL | |
| normal_position | varchar(16) | YES | | NULL | |
+-----------------+--------------+------+-----+---------+----------------+
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| pnp_id | int(11) | NO | PRI | NULL | auto_increment |
| devices_id | int(11) | NO | MUL | NULL | |
| pnp_num | varchar(45) | NO | | NULL | |
+------------+-------------+------+-----+---------+----------------+
I am trying to get results formatted as follows (NULL values appear as blanks):
+------------+-------------+-----------------------+
| devices_id | description | pnpnum |
+------------+-------------+-----------------------+
| 1 | ex | 1234 |
| 2 | ex2 | 2345 |
| 3 | ex3 | |
| 4 | ex4 | 3456, 4567, 5678, 6879|
+------------+-------------+-----------------------+
Using the following SQL query,
SELECT *, GROUP_CONCAT(pnp.pnp_num separator ', ') pnpnum
FROM devices
JOIN pnp ON devices.devices_id = pnp.devices_id
WHERE devices.machine_id = 1
GROUP BY devices.devices_ID
ORDER BY devices.description;
my results are relatively close, however, I am unable to include a device if it has a null pnpnum.
+------------+-------------+-----------------------+
| devices_id | description | pnpnum |
+------------+-------------+-----------------------+
| 1 | ex | 1234 |
| 2 | ex2 | 2345 |
| 4 | ex4 | 3456, 4567, 5678, 6879|
+------------+-------------+-----------------------+
What is it that I am missing from my SQL statement that will allow me to include null values?
You need to use LEFT JOIN because even if there isn't a match, it will return all the results from the left table leaving the fields from the right table null.

Select tracks and the date that has maximum visits

Here is the deal. I have two tables
tracks
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| track_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| artist_id | int(11) | YES | | NULL | |
| genre_id | int(11) | YES | | NULL | |
| track_artist | varchar(255) | YES | | NULL | |
| track_title | varchar(255) | NO | | NULL | |
| track_lyric | text | YES | | NULL | |
| track_video | varchar(255) | YES | | NULL | |
| play_url | varchar(255) | YES | | NULL | |
| shares | int(11) | NO | | 0 | |
| likes | int(11) | NO | | 0 | |
| dislikes | int(11) | NO | | 0 | |
| is_active | enum('T','F') | NO | | T | |
| created_at | int(10) | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
track_visits
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| track_visit_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| track_id | int(11) | NO | MUL | NULL | |
| ip_address | varchar(255) | NO | | NULL | |
| created_at | int(10) | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
And the question is:
How can I select all the tracks and the date that has maximum visits for every specific track?
Regards
Nasko
Since you are using MySql, you can use this:
SELECT tracks.*, track_visits.*
FROM
tracks LEFT JOIN (
SELECT track_id, MAX(created_at) MaxCreatedAt
FROM track_visits
GROUP BY track_id) mx
ON tracks.track_id=mx.track_id
LEFT JOIN track_visits
ON mx.track_id=track_visits.track_id
AND mx.MaxCreatedAt=track_visits.created_at
GROUP BY
tracks.track_id