inner join on multiple tables, count & distinct - mysql

I have 3 tables and I am trying to join those tables with inner join. however when I use count(distinct column_id) it mysql through error which is
SQL syntax : check
for the right syntax to use near '(DISTINCT as_ticket.vehicle_id) FROM as_vehicle INNER JOIN as_ticket
My Query
SELECT
`as_vehicle`.`make`, `as_vehicle`.`model`, `as_odometer`.`value`
COUNT (DISTINCT `as_ticket`.`vehicle_id`)
FROM `as_vehicle`
INNER JOIN `as_ticket`
ON `as_vehicle`.`vehicle_id` = `as_ticket`.`vehicle_id`
INNER JOIN `as_odometer`
ON `as_odometer`.`vehicle_id` = `as_vehicle`.`vehicle_id`
WHERE `as_ticket`.`vehicle_id` = 7
ORDER BY `as_odometer`.`value`
DESC
Tbl as_vehicle
+------------+-------------+---------+
| vehicle_id |make | model |
+------------+-------------+---------|
| 1 | HYUNDAI | SOLARIS |
| 2 | A638EA15 | ACCENT |
+-------------+------------+---------+
Tbl as_odometer;
+------------+-------+
| vehicle_id | value |
+------------+-------+
| 1 | 10500 |
| 5 | 20000 |
| 1 | 20000 |
+------------+-------+
Tbl service
+-----------+------------+
| ticket_id | vehicle_id |
+-----------+------------+
| 1 | 1 |
| 2 | 1 |
+-----------+------------+

You forgot a comma before count.
SELECT `as_vehicle`.`make`, `as_vehicle`.`model`, `as_odometer`.`value`,
count(DISTINCT `as_ticket`.`vehicle_id`) // here ---^

First, you should not have a space after the count() and you have a missing comma (as already noted). More importantly, you don't have a group by, so your query will return one row.
And, because of the where clause, the value will always be "1". You have restricted the query to just one vehicle id.
I suspect the query you want is more like:
SELECT `as_vehicle`.`make`, `as_vehicle`.`model`, `as_odometer`.`value`
COUNT(*)
FROM `as_vehicle` INNER JOIN
`as_ticket`
ON `as_vehicle`.`vehicle_id` = `as_ticket`.`vehicle_id` INNER JOIN
`as_odometer`
ON `as_odometer`.`vehicle_id` = `as_vehicle`.`vehicle_id`
WHERE `as_ticket`.`vehicle_id` = 7
GROUP BY `as_vehicle`.`make`, `as_vehicle`.`model`, `as_odometer`.`value`
ORDER BY `as_odometer`.`value` DESC;
Also, you should learn to use table aliases and all those backquotes don't help the query.

Related

How to exclude rows when a certain condition is met in MySQL

I have two datatables. One table contains information of participants (Participants). And a table which contains all registrations for the event (Registrars).
+----+-------+
| id | name |
+----+-------+
| 1 | Peter |
+----+-------+
| 2 | John |
+----+-------+
+-----------+----------+
| person_id | event_id |
+-----------+----------+
| 1 | 1 |
+-----------+----------+
| 2 | 2 |
+-----------+----------+
| 2 | 1 |
+-----------+----------+
I run a MySQL query to get the information of registrars of an event. The query looks like this:
SELECT name
FROM Participants
INNER JOIN Registrars
ON Participants.id=Registrars.person_id
WHERE
event_id = 1
Now I want to build a query where if the participant also registered for event 2 it will not be returned in the result of the query the reg. How can I achieve this in one query?
You can group by participant and use conditional aggregation in the HAVING clause to set the conditions:
SELECT p.id, p.name
FROM Participants p INNER JOIN Registrars r
ON p.id = r.person_id
WHERE r.event_id IN (1, 2)
GROUP BY p.id, p.name
HAVING MAX(r.event_id = 1) = 1
AND MAX(r.event_id = 2) = 0
You can extend the code by adding more conditions in a similar way.
SELECT name
FROM Participants as p
INNER JOIN Registrars as reg
ON P.id=Reg.person_id
WHERE
reg.event_id = 1
and not exists (select 1 from Registrars as strr where strr.event_id=2 and p.id=strr.person_id )

Inner Join 2 tables multiple result

i have 2 tables, one for the products and one for the sizes.
they have a relation with fk and the problem is that when I'm using the inner join I cannot use the "group by" in order to don't have repeated results.
this is the code:
SELECT
sneakers.sneaker_id,
sneakers.sneaker_name,
sneakers.gender,
sneakers.description,
sneakers.price,
sizes.size,
brand_names.brand_name
FROM sneakers
INNER JOIN sizes ON sneaker_fk = sneaker_id
if i try to use the GROUP BY sneaker_fk it will give me this response:
Error
SQL query: Documentation
SELECT sneakers.sneaker_id,sneakers.sneaker_name, sneakers.gender, sneakers.description,
sneakers.price, sizes.size, brand_names.brand_name FROM sneakers
INNER JOIN sizes ON sneaker_fk = sneaker_id
INNER JOIN brand_names ON brand_name_fk = brand_name_id
GROUP BY sneaker_fk LIMIT 0, 30
MySQL said: Documentation
#1055 - Expression #6 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'sneakerstore.sizes.size' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
What am I doing wrong??
Do you have any better solution to display One item with all the related sizes without having multiple results?
I hope you can help me as fast as possible!
thanks in advance
Use MySQL's Group_Concat() function
The MySQL GROUP_CONCAT() function returns a string with concatenated non-NULL value from a group.
Excerpt from Using GROUP_CONCAT with joined tables
GROUP_CONCAT works with joins as well.
Let's say we have a table courses:
| id | name |
+—-+—————+
| 1 | Ruby 101 |
+—-+—————+
| 2 | TDD for Poets |
+—-+—————+'
We also have a second table bookings:
| id | course_id |
+—-+———–+
| 7 | 1 |
+—-+———–+
| 8 | 1 |
+—-+———–+
| 9 | 1 |
+—-+———–+
| 10 | 2 |
+—-+———–+
| 11 | 2 |
+—-+———–+
SELECT courses.name, GROUP_CONCAT(bookings.id)
FROM bookings
INNER JOIN courses ON courses.id == bookings.course_id
GROUP BY bookings.course_id;
The result set looks like this:
| courses.name | GROUP_CONCAT(bookings.id) |
+—————+—————————+
| Ruby 101 | 7,8,9 |
+—————+—————————+
| TDD for Poets | 10,11 |
+—————+—————————+

Select latest value of another column based on a comparison between unique keys

What I'm trying to achieve is to fetch the latest date of another column based on the same msisdn (if there exists more than one msisdn that is linked to other imsis). (You can assume imsi is more of a unique column)
(Tables are simplified for demonstration purposes)
I've two tables like the following:
operator table
+--------+--------+---------------------+
| imsi | msisdn | last_accessed |
+--------+--------+---------------------+
| 74583 | 004442 | 2018-04-05 16:20:32 |
+--------+--------+---------------------+
| 94210 | 023945 | 2017-02-13 11:27:14 |
+--------+--------+---------------------+
| 59123 | 004442 | 2018-07-15 05:24:55 |
+--------+--------+---------------------+
| 61234 | 089923 | 2018-07-21 16:13:29 |
+--------+--------+---------------------+
customer table
+--------+--------------+---------------------+
| imsi | company_id | business_plan |
+--------+--------------+---------------------+
| 74583 | FEX | yearly |
+--------+--------------+---------------------+
| 94210 | AOH | trial |
+--------+--------------+---------------------+
| 59123 | BIOI | monthly |
+--------+--------------+---------------------+
| 61234 | OOX | simple |
+--------+--------------+---------------------+
The following result is what I aim for. If I search for 74583 it should return 2018-07-15 05:24:55.
+--------+--------------+---------------------+----------------------+
| imsi | company_id | business_plan | last_accessed_date |
+--------+--------------+---------------------+----------------------+
| 74583 | FEX | yearly | 2018-07-15 05:24:55 |
+--------+--------------+---------------------+----------------------+
The following query returns almost what I try to achieve but does not return the latest date according to the table above.
SELECT
cust.imsi,
cust.company_id,
cust.business_plan,
CASE
WHEN
(
SELECT MAX(subop.last_accessed)
FROM operator subop
WHERE subop.msisdn = op.msisdn
GROUP BY subop.msisdn
HAVING COUNT(*) > 1
)
THEN
op.last_accessed
ELSE
'Never'
END
AS last_accessed_date
FROM customer cust
INNER JOIN operator op
ON cust.imsi = op.imsi
WHERE cust.imsi = '74583';
We can try doing this using a correlated subquery in the select clause:
SELECT
c.imsi,
c.company_id,
c.business_plan,
(SELECT MAX(t.last_accessed) FROM operator t
WHERE t.msisdn = o.msisdn) last_accessed_date
FROM customer c
INNER JOIN operator o
ON c.imsi = o.imsi
WHERE c.imsi = '74583';
Follow the link below for a SQLFiddle demo.
Demo
This query will return the last_accessed_date for every imsi:
select
o1.imsi,
o1.msisdn,
max(o2.last_accessed) as last_accessed_date
from
operator o1 inner join operator o2
on o1.msisdn = o2.msisdn
group by
o1.imsi,
o1.msisdn
(I am joining the operators table with itself to get the last accessed date based on the msisdn column). Then you can join this query with the customer table:
select
c.imsi,
c.company_id,
c.business_plan,
coalesce(l.last_accessed_date, 'Never') as last_accessed_date
from
customer c left join (
select
o1.imsi,
o1.msisdn,
max(o2.last_accessed) as last_accessed_date
from
operator o1 inner join operator o2
on o1.msisdn = o2.msisdn
group by
o1.imsi,
o1.msisdn
) l on c.imsi = l.imsi
it can then be written in some different ways, but I think this is the easier to understand.
Please see a fiddle here http://sqlfiddle.com/#!9/0f080c/1
Try this
SELECT
cust.imsi,
cust.company_id,
cust.business_plan,
(
SELECT MAX(last_accessed) FROM operator AS a WHERE a.msisdn = op.msisdn
) AS last_accessed_date
FROM customer cust
INNER JOIN operator op
ON cust.imsi = op.imsi
WHERE cust.imsi = '74583'

Mysql join select max for all record

I am unable to map the record as my expectation.
Doc Table
-------+-------------------
doc_id | doc_title
-------+-------------------
1 | My book
-------+-------------------
2 | My sec Book
--------------------------
Doc details Table
-----------+--------------+-----------------------
fk_doc_id | doc_version | submit_date
-----------+--------------+-----------------------
1 | 1 | 2015-10-25 14:32:01
-----------+--------------+-----------------------
1 | 2 | 2015-10-26 13:00:01
-----------+--------------+-----------------------
1 | 3 | 2015-10-27 09:00:00
--------------------------+-----------------------
2 | 1 | 2015-10-25 11:15:01
-----------+--------------+-----------------------
2 | 2 | 2015-10-26 10:00:00
--------------------------+-----------------------
Question: How do I join this two tables to get each documents with the latest version doc info? even though I get the latest version but the row info which is not correct.
So far I have tried this query
SELECT *, max(doc_version) AS latest_version
FROM d_doc
JOIN d_doc_dtl ON d_doc.doc_id = d_doc_dtl.fk_doc_id
GROUP BY d_doc.doc_id;
My expected result is
--------+--------------+----------------+--------------------
doc_id | doc_title | latest_version | submit_date
--------+--------------+----------------+--------------------
1 | My book | 3 | 2015-10-27 09:00:00
--------+--------------+----------------+--------------------
2 | My sec book | 2 | 2015-10-26 10:00:00
----------------------------------------+--------------------
but my result is
--------+--------------+----------------+--------------------
doc_id | doc_title | latest_version | submit_date
--------+--------------+----------------+--------------------
1 | My book | 3 | 2015-10-25 14:32:01
--------+--------------+----------------+--------------------
2 | My sec book | 2 | 2015-10-25 11:15:01
----------------------------------------+--------------------
NOTE: the submit_date which is no correct.
SELECT d_doc.doc_id, d_doc.doc_title, max_table.latest_version
FROM d_doc JOIN (
select fk_doc_id, max(doc_version) as latest_version from d_doc_dtl group by fk_doc_id
) as max_table ON d_doc.doc_id = max_table.fk_doc_id
This query should work as you expect. It selects latest document versions in inner subquery and than joins it with documents.
SELECT d.doc_id,
d.doc_title,
dtl.doc_version latest_version,
dtl.submit_date
FROM d_doc d
INNER JOIN (SELECT dt.*
FROM d_doc_dtl dt
INNER JOIN (SELECT fk_doc_id, MAX(doc_version) doc_version
FROM d_doc_dtl
GROUP BY fk_doc_id) dm
ON dt.fk_doc_id = dm.fk_doc_id
AND dt.doc_version = dm.doc_version) dtl
ON d.doc_id = dtl.fk_doc_id
You get wrong results because you selected only max(version), but date as it is not in group by clause can contain any value. First you need to get records containing latest version as shown above.
Easy, instead of
SELECT *, max(doc_version) AS latest_version
Use this
SELECT d_doc.*, max(doc_version) AS latest_version
What you were doing by selecting * is getting all the results after the table is joined and you only wanted the original table results.
select * from doc_table , doc_version where exists( select
max(version_id)
from
doc_version vert
where
(doc_table .DOC_ID = vert.VERSION_DOC_ID) ) group by doc_id;
You can try something like this.

mysql subquery not producing all results

I have two tables: contacts and client_profiles. A contact has many client_profiles, where client_profiles has foreign key contact_id:
contacts:
mysql> SELECT id,first_name, last_name FROM contacts;
+----+-------------+-----------+
| id | first_name | last_name |
+----+-------------+-----------+
| 10 | THERESA | CAMPBELL |
| 11 | donato | vig |
| 12 | fdgfdgf | gfdgfd |
| 13 | some random | contact |
+----+-------------+-----------+
4 rows in set (0.00 sec)
client_profiles:
mysql> SELECT id, contact_id, created_at FROM client_profiles;
+----+------------+---------------------+
| id | contact_id | created_at |
+----+------------+---------------------+
| 6 | 10 | 2014-10-09 17:17:43 |
| 7 | 10 | 2014-10-10 11:38:01 |
| 8 | 10 | 2014-10-10 12:20:41 |
| 9 | 10 | 2014-10-10 12:24:19 |
| 11 | 12 | 2014-10-10 12:35:32 |
+----+------------+---------------------+
I want to get the latest client_profiles for each contact. That means There should be two results. I want to use subqueries to achieve this. This is the subquery I came up with:
SELECT `client_profiles`.*
FROM `client_profiles`
INNER JOIN `contacts`
ON `contacts`.`id` = `client_profiles`.`contact_id`
WHERE (client_profiles.id =
(SELECT `client_profiles`.`id` FROM `client_profiles` ORDER BY created_at desc LIMIT 1))
However, this is only returning one result. It should return client_profiles with id 9 and 11.
What is wrong with my subquery?
It looks like you were trying to filter twice on the client_profile table, once in the JOIN/ON clause and another time in the WHERE clause.
Moving everything in the where clause looks like this:
SELECT `cp`.*
FROM `contacts`
JOIN (
SELECT
`client_profiles`.`id`,
`client_profiles`.`contact_id`,
`client_profiles`.`created_at`
FROM `client_profiles`
ORDER BY created_at DESC
LIMIT 1
) cp ON `contacts`.`id` = `cp`.`contact_id`
Tell me what you think.
Should be something like maybe:
SELECT *
FROM `client_profiles`
INNER JOIN `contacts`
ON `contacts`.`id` = `client_profiles`.`contact_id`
GROUP BY `client_profiles`.`contact_id`
ORDER BY created_at desc;
http://sqlfiddle.com/#!2/a3f21b/9
You need to prequery the client profiles table grouped by each contact.. From that, re-join to the client to get the person, then again to the client profiles table based on same contact ID, but also matching the max date from the internal prequery using max( created_at )
SELECT
c.id,
c.first_name,
c.last_name,
IDByMaxDate.maxCreate,
cp.id as clientProfileID
from
( select contact_id,
MAX( created_at ) maxCreate
from
client_profiles
group by
contact_id ) IDByMaxDate
JOIN contacts c
ON IDByMaxDate.contact_id = c.id
JOIN client_profiles cp
ON IDByMaxDate.contact_id = cp.contact_id
AND IDByMaxDate.maxCreate = cp.created_at