SQL: join select multiple tables with missing row - mysql

I have a big multiple table query join select where some values are optional.
This is the query:
SELECT a.date_in, a.date_out, b.name, b.phone, b.birthdate,
b.country, b.hotel, b.room_nr, b.passport_nr, c.email,
d.size, e.name, GROUP_CONCAT(DISTINCT g.service), GROUP_CONCAT(DISTINCT h.service)
, GROUP_CONCAT(DISTINCT i.time), GROUP_CONCAT(DISTINCT j.location)
FROM reservation a, rider b, user c,
bike_size d, bike e, services_reservation f, services g,
bike_shipping h, bike_shipping_reservation i
, bike_shipping_location j WHERE a.rider_id = b.id
AND b.user_id = c.id AND a.bike_size_id = d.id AND
d.bike_id = e.id AND a.id = f.reservation_id AND
f.services_id = g.id
AND h.id = i.bike_shipping_id AND a.id = i.reservation_id
AND i.bike_shipping_location_id = j.id
AND a.id = 80
In the tables from the query above, the table named services_reservation with the following columns (id, services_id, reservation_id) is completely empty in this case, which makes the values that I select from the table bike_shipping_reservation NULL.
How can I make some tables that I select from optional in case they are empty?
Here is the SQL Fiddle with 1 empty table, you can see the NULL results at the end (only GROUP_CONCAT(DISTINCT g.service) should be NULL).
http://sqlfiddle.com/#!9/ee31b/6
Here is the SQL Fiddle with all tables having values in there columns, you can see that all values are returned not NULL.
http://sqlfiddle.com/#!9/8bc033/34
Any thoughts?

Use left join where the table (or the row) are empty on don't match
SELECT a.date_in, a.date_out, b.name, b.phone, b.birthdate,
b.country, b.hotel, b.room_nr, b.passport_nr, c.email,
d.size, e.name, GROUP_CONCAT(DISTINCT g.service), GROUP_CONCAT(DISTINCT h.service)
, GROUP_CONCAT(DISTINCT i.time), GROUP_CONCAT(DISTINCT j.location)
FROM reservation a
INNER JOIN rider b on a.rider_id = b.id
INNER JOIN user c on b.user_id = c.id
INNER JOIN bike_size d on a.bike_size_id = d.id
INNER JOIN bike e ON d.bike_id = e.id
LEFT JOIN services_reservation f on a.id = f.reservation_id
INNER JOIN services g on f.services_id = g.id
INNER JOIN bike_shipping_reservation i on a.id = i.reservation_id
INNER JOIN bike_shipping h ON h.id = i.bike_shipping_id
INNER JOIN bike_shipping_location j on i.bike_shipping_location_id = j.id
where a.id = 80

Related

MySQL Multiple JOIN with most resent timestamp from one

I have problem that I hope someone can help me with.
SELECT a.country_name, s.state_name, c.city_id,
LEAST (c.next_1, c.next_2, c.next_3) AS next_visit,
MAX(v.visit_time) AS last_visit
FROM city c
INNER JOIN country a ON a.id = c.country
INNER JOIN state s ON s.id = c.state
INNER JOIN visit_log v ON CONCAT(c.country, c.state, c.city_id) = CONCAT(v.country, v.state, v.city_id)
GROUP BY CONCAT(v.country, v.state, v.city_id)
ORDER BY a.id ASC, s.id ASC, c.city_id
My main problem now is that I can't get the col_1 and col_2 from the visit_log corresponding with MAX(visit_log)
SQLfiddle
You can add the "latest" requirement to the join condition:
SELECT *
FROM city c
JOIN country a
ON a.id = c.country
JOIN state s
ON s.id = c.state
JOIN visit_log v
ON v.country = c.country
AND v.state = c.state
AND v.city_id = c.city_id
AND visit_time =
(
SELECT MAX(visit_time)
FROM visit_log v2
WHERE v2.country = c.country
AND v2.state = c.state
AND v2.city_id = c.city_id
)
You can find many other approaches in the greatest-n-per-group+mysql tag. For optimal speed you'd use an approach using variables.
You can try this:-
SELECT C.NAME, S.NAME, CN.ID, NV.Next_visit_1, VL.visited
FROM COUNTRY C INNER JOIN next_visit NV ON C.ID = NV.Country
INNER JOIN STATE S ON NV.State = S.ID
JOIN CITY
INNER JOIN visitor_log VL ON CONCAT(NV.country, NV.state, NV.city) = CONCAT(VL.country, VL.state, VL.city)

Mysql Group concat and then queries based on results

Hi all I have a table business which has alot of many to many relationships. It was suggested i perform a group concat first to get the ideas from the many table and then look at these ids to get the values from the many tables
In the below instance OK i can see i get a list of announcement ids back via the GROUP_CONCAT(DISTINCT ba.announcement_id) as 'announcement', how from here do i set
SELECT * from announcement
where id IN(_______)
where the in represents what was returned from the group_concat
id b
BEGIN
/* Business Information and Categories */
SELECT
b.alias_title, b.title, b.premisis_name,
a.address_line_1, a.address_line_2, a.postal_code,tvc.town_village_city,spc.state_province_county, c.country,
GROUP_CONCAT(DISTINCT be.event_id) as 'event',
GROUP_CONCAT(DISTINCT ba.announcement_id) as 'announcement',
GROUP_CONCAT(DISTINCT bd.document_id) as 'document',
GROUP_CONCAT(DISTINCT bi.image_id) as 'image',
GROUP_CONCAT(DISTINCT bprod.product_id ) as 'product',
GROUP_CONCAT(DISTINCT bt.tag_title_id) as 'tag'
FROM business AS b
INNER JOIN business_category bc_1 ON b.primary_category = bc_1.id
INNER JOIN business_category bc_2 ON b.secondary_category = bc_2.id
LEFT OUTER JOIN business_category bc_3 ON b.tertiary_category = bc_3.id
INNER JOIN address a ON b.address_id = a.id
LEFT OUTER JOIN town_village_city tvc ON a.town_village_city_id = tvc.id
LEFT OUTER JOIN state_province_county spc ON a.state_province_county_id
INNER JOIN country c ON a.country_id = c.id
LEFT OUTER JOIN geolocation g ON b.geolocation_id = g.id
LEFT OUTER JOIN business_event be ON b.id = be.event_id
LEFT OUTER JOIN business_announcement ba ON b.id = ba.announcement_id
LEFT OUTER JOIN business_document bd ON b.id = bd.business_id
LEFT OUTER JOIN business_image bi ON b.id = bi.business_id
LEFT JOIN business_property bp ON b.id= bp.business_id
LEFT JOIN business_product bprod ON b.id= bprod.business_id
LEFT JOIN business_tag bt ON b.id = bt.business_id
WHERE b.id= in_business_id;
SELECT * from announcement
where
END
In your first select statement you may assign the announcementId's to a variable and then use it to get all announcements in the second query:
set #announcementIds = '';
select ...........,
#announcementIds:= GROUP_CONCAT(DISTINCT announcement_id) as 'announcement',
...........;
Select * from announcement
where announcement_id REGEXP REPLACE(#announcementIds,',','|');
Some links:
Replace function
Regexp

Optimizing this SQL Query

How would you optimize the following query?
'example_companies' contains companies data.
'example_roles_companies' contains companies roles (pivot)
'example_industries_companies' contains companies industries (pivot)
SELECT DISTINCT a.id,
a.mode,
a.name,
a.city,
b.name AS USER,
b.phone
FROM example_companies a
LEFT JOIN example_users b
ON a.contact_id = b.id
LEFT JOIN example_roles_companies c
ON a.id = c.company_id
WHERE "2" IN (SELECT industry_id
FROM example_industries_companies
WHERE company_id = a.id)
AND c.role_id = 2
AND a.account_mode != 2
ORDER BY a.id
Query:
SELECT DISTINCT a.id,
a.mode,
a.name,
a.city,
b.name AS USER,
b.phone
FROM example_companies a
LEFT JOIN example_users b ON a.contact_id = b.id
INNER JOIN example_roles_companies c ON a.id = c.company_id AND c.role_id = 2
INNER JOIN example_industries_companies i
ON i.company_id = a.id AND i.industry_id = "2"
WHERE
a.account_mode != 2
ORDER BY
a.id
Structure:
Index on a.id, not null
Index on b.id, not null [analyze the opportunity of adding another index (b.id, b.name, b.phone) to this table as well]
Index on (c.company_id, c.role_id) not null both
Index on (i.company_id, i.industry_id), not null both
Remarks:
Please note that your industry_id = "2" seems weird to me, ids are generally numbers and if they are not then it should be looked since integers are faster to process than strings. Additionally, this way of double-quoting is not usual in mysql. Are you sure of your syntax?

join two inline tables - unknown column?

I'm getting "Error Code: 1054. Unknown column 'E1.extensao' in 'field list'". I changed table names but my query is as follows:
SELECT E1.stateName, E1.city, E1.boughtEnough, E2.bought
FROM
(SELECT count(DISTINCT idClient),city,stateName FROM
(SELECT
max(n.ordervalue) as boughtEnough,
m.idClient,
i.nome AS city,
i.id AS cityId,
i.stateName
FROM Clients c
INNER JOIN client_order m ON c.idClient = m.idClient
INNER JOIN orders n ON m.client_order = n.client_order
INNER JOIN orderDetail p ON n.idorder = p.idorder
AND p.idCurso = m.idCurso
INNER JOIN cities i ON c.city = i.id
WHERE
m.idCurso = '10'
GROUP BY
m.idClient,
i.nome,
i.id,
i.stateName
HAVING max(n.orders) >= 6) t
GROUP BY t.city, t.stateName
ORDER BY t.stateName,t.city) E1
JOIN (SELECT count(DISTINCT idClient),city,stateName FROM
(SELECT
count(n.ordervalue) as bought,
m.idClient,
i.nome AS city,
i.id AS cityId,
i.stateName
FROM Clients c
INNER JOIN client_order m ON c.idClient = m.idClient
INNER JOIN orders n ON m.client_order = n.client_order
INNER JOIN orderDetail p ON n.idorder = p.idorder
AND p.idCurso = m.idCurso
INNER JOIN cities i ON c.city = i.id
WHERE
m.idCurso = '10'
GROUP BY
m.idClient,
i.nome,
i.id,
i.stateName
HAVING ((max(n.orders) < 6) AND (count(n.orders) >= 1))) t
GROUP BY t.city, t.stateName
ORDER BY t.stateName,t.city) E2 ON E1.cityId = E2.cityId
I'm more used to SQL Server, not MySQL. What am I getting wrong?
I assume that E1.extensao means E1.boughtEnough? Look closely at how E1 is defined:
(SELECT count(DISTINCT idClient),city,stateName FROM
(SELECT
max(n.ordervalue) as boughtEnough,
...) t
...) E1
There's a t.boughtEnough, but you're not "passing it up" to E1.

only returning records when s.id = u.summary_id

select
s.id, s.description, s.improvement, s.previous_year_id,
s.current_year_id, s.first_name, s.last_name, s.username,
s.finding, s.action, s.share, s.learned, s.timestamp,
d.title as department_title,
group_concat(g.title SEPARATOR \' | \') as strategic_goals,
y1.year as current_year_title, y2.year as previous_year_title,
u.summary_id, u.file_name as file_name
from
summary s, year y1, year y2, strategic_goal_entries sge,
goal g, department d, uploads u
where
s.id = sge.summary_id
and
s.current_year_id = y1.id
and
s.previous_year_id = y2.id
and
sge.goal_id = g.id
and
s.id = u.summary_id
and
s.department_id = d.id
and
s.department_id = '4'
group by
s.id
This only returns records from the summary table that has a relating record in the uploads table (s.id = uploads.summary_id) that contain a value within the uploads.summary_id field
I want to return all records, whether or not it has a file associated with it.
Any help is appreciated.
Suggest refactoring this SQL query to use ANSI joins. To achive your goal, you'd want a LEFT JOIN instead:
SELECT /*your columns*/
from summary s
INNER JOIN year y1 ON s.current_year_id = y1.id
INNER JOIN year y2 ON s.previous_year_id = y2.id
INNER JOIN strategic_goal_entries sge ON s.id = sge.summary_id
INNER JOIN goal g ON sge.goal_id = g.id
INNER JOIN department d ON s.department_id = d.id
LEFT JOIN uploads u ON s.id = u.summary_id
WHERE s.department_id = '4'
group by s.id