I am new to SQL and I'm having difficulties writing the following query.
Scenario
A user has two addresses, home address (App\User) and listing address (App\Listing). When a visitor searches for listings for a Suburb or postcode or state, if the user's listing address does not match - but if home address does match - they will be in the search result too.
For example: if a visitor searches for Melbourne, I want to include listings from Melbourne and also the listings for the users who have an address in Melbourne.
Expected output:
user_id first_name email suburb postcode state
1 Mathew mathew.afsd#gmail.com Melbourne 3000 VIC
2 Zammy Zamm#xyz.com Melbourne 3000 VIC
Tables
users:
id first_name email
1 Mathew mathew.afsd#gmail.com
2 Zammy Zamm#xyz.com
3 Tammy tammy#unknown.com
4 Foo foo#hotmail.com
5 Bar bar#jhondoe.com.au
listings:
id user_id hourly_rate description
1 1 30 ABC
2 2 40 CBD
3 3 50 XYZ
4 4 49 EFG
5 5 10 Efd
addresses:
id addressable_id addressable_type post_code suburb state latitude longitude
3584 1 App\\User 2155 Rouse Hill NSW -33.6918372 150.9007221
3585 2 App\\User 3000 Melbourne VIC -33.6918372 150.9007221
3586 3 App\\User 2000 Sydney NSW -33.883123 151.245969
3587 4 App\\User 2008 Chippendale NSW -33.8876392 151.2011224
3588 5 App\\User 2205 Wolli Creek NSW -33.935259 151.156301
3591 1 App\\Listing 3000 Melbourne VIC -37.773923 145.12385
3592 2 App\\Listing 2030 Vaucluse NSW -33.858935 151.2784079
3597 3 App\\Listing 4000 Brisbane QLD -27.4709331 153.0235024
3599 4 App\\Listing 2000 Sydney NSW -33.91741 151.231307
3608 5 App\\Listing 2155 Rouse Hill NSW -33.863464 151.271504
Try this. You can check it here.
SELECT l.*
FROM listings l
LEFT JOIN addresses a_l ON a_l.addressable_id = l.id
AND a_l.addressable_type = "App\\Listing"
AND a_l.suburb = "Melbourne"
LEFT JOIN addresses a_u ON a_u.addressable_id = l.user_id
AND a_u.addressable_type = "App\\User"
AND a_u.suburb = "Melbourne"
WHERE a_l.id IS NOT NULL OR a_u.id IS NOT NULL
As per my understanding of your question, for any suburb - supplied by a visitor, you want to include all the listings where either User's address is the same as the suburb supplied or the Listing's address is the same as the suburb supplied.
Assuming addressable_id column is related to Id of Users table and Listings table, based on value in addressable_type column, you can use the following query to join and get the desired result:
Select l.*
From Listings l
inner join Addresses a on ((a.addressable_id = l.user_Id and a.addressable_type = 'App\\User') or (a.addressable_id = l.Id and a.addressable_type = 'App\\Listings'))
inner join Addresses a1 On a1.addressable_id = a.addressable_id and a1.Suburb = 'Melbourne'
try this,
SELECT
a.addressable_id AS `userid`,
b.first_name AS `username`
FROM
addresses AS a JOIN users AS b ON a.addressable_id=b.id
WHERE
a.suburb = 'Melbourne';
if < addressable_id > has relation with < id > in listing table,
SELECT
a.addressable_id AS `userid`,
b.first_name AS `username`
FROM
addresses AS a JOIN users AS b ON a.addressable_id=b.id AND addressable_type='App\\User'
WHERE
a.suburb = 'Melbourne'
UNION
SELECT
b.user_id AS `userid`,
c.first_name AS `username`
FROM
addresses AS a JOIN listings AS b ON a.addressable_id=b.id AND addressable_type='App\\Listing'
JOIN users AS c ON b.user_id=c.id
WHERE
a.suburb = 'Melbourne';
Related
I have a big issue for my "traveling offer" project, working 99% OK, but not 100%.
I have main table with offers, where each offer can have set multiple department cities as well as multiple destination cities (this is reduced sample with reduced columns).
For example, I'm offering some travels from England, where department cities can be from London, Leeds and Manchester. Destination cities are Prague, Bratislava, Budapest and Belgrade.
Offer 1 is set to department cities London or Leeds, and destinations are Prague and Budapest.
Offer 2 is set to department city London, and destinations are Bratislava and Belgrade.
Offer 3 is set to department city Manchester or Leeds, and destination is Prague.
Table offers
----------------------------
id title price
----------------------------
1 Offer 1 title 300 Eur
2 Offer 2 title 250 Eur
3 Offer 3 title 350 Eur
Now relation tables and city name tables
Table departments
----------------------------
id name
----------------------------
1 London
2 Leeds
3 Manchester
relation Table rel_departments
------------------------
offer_id rel_id
------------------------
1 1
1 2
2 1
3 2
3 3
Table destinations
----------------------------
id name
----------------------------
1 Prague
2 Bratislava
3 Budapest
4 Belgrade
relation Table rel_destinations
------------------------
offer_id rel_id
------------------------
1 1
1 3
2 2
2 4
3 1
As SQL result I expect for each offer concatenated values bot for department cities and destination cities
If I search all with following sql I got OK result:
SELECT offers.*,
GROUP_CONCAT(DISTINCT DEPC.name SEPARATOR ', ') AS depCities,
GROUP_CONCAT(DISTINCT DESTC.name SEPARATOR ', ') AS destCities
FROM offers
INNER JOIN `rel_departments` ON (`rel_departments`.`offer_id` = `offers`.`id`)
INNER JOIN `departments` as DEPC ON (DEPC.`id` = `rel_departments`.`rel_id`)
INNER JOIN `rel_destinations` ON (`rel_destinations`.`offer_id` = `offers`.`id`)
INNER JOIN `destinations` as DESTC ON (DESTC.`id` = `rel_destinations`.`rel_id`)
GROUP BY offers.id
result would be okay:
---------------------------------------------------------------------
id title price depCities destCities
---------------------------------------------------------------------
1 Offer 1 title 300 Eur London, Leeds Prague, Budapest
2 Offer 2 title 250 Eur London Bratislava, Belgrade
3 Offer 3 title 350 Eur Leeds, Manchester Prague
And I need results like this whatever WHERE clause is. But, whenever I put where clause, I loose one of results in concatenation. For example, I search for all offers with Prague as a destination. If I add to the end of the sql statement:
where rel_destinations.rel_id=1
result is as following:
---------------------------------------------------------------------
id title price depCities destCities
---------------------------------------------------------------------
1 Offer 1 title 300 Eur London, Leeds Prague
3 Offer 3 title 350 Eur Leeds, Manchester Prague
If you can notice, there is no Budapest in offer 1. What to do to get complete concatenation string... Not that WHERE clause can be more complex, i.e. to search for department city or any other parameter.
Any help is appreciated :)
You need to use a different join with rel_destinations to get the offers with Prague as a destination. Join this with your original query.
SELECT offers.*,
GROUP_CONCAT(DISTINCT DEPC.name SEPARATOR ', ') AS depCities,
GROUP_CONCAT(DISTINCT DESTC.name SEPARATOR ', ') AS destCities
FROM offers
INNER JOIN `rel_departments` ON (`rel_departments`.`offer_id` = `offers`.`id`)
INNER JOIN `departments` as DEPC ON (DEPC.`id` = `rel_departments`.`rel_id`)
INNER JOIN `rel_destinations` ON (`rel_destinations`.`offer_id` = `offers`.`id`)
INNER JOIN `destinations` as DESTC ON (DESTC.`id` = `rel_destinations`.`rel_id`)
INNER JOIN rel_destinations AS d1 ON d1.offer_id = offers.id
WHERE d1.rel_id = 1
GROUP BY offers.id
DEMO
I am in need of generating a result which joins two user related tables - Users and Usermeta. These are from a Wordpress MySQL DB.
User Table -
ID user_email
1 abc#gmail.com
2 xyz#gmail.com
3 1sf#email.com
Usermeta Table -
Umeta_ID user_id meta_key meta_value
1000 1 billing_phone 9876443100
1001 1 billing_postcode 670001
1002 1 billing_address Somewhere here, Delhi
1003 2 billing_phone 9876345188
1004 2 billing_postcode 650021
1005 2 billing_address 7th Lane, Bangalore
1003 3 billing_phone 7852562100
1004 3 billing_postcode 400521
1005 3 billing_address Fancy Area, Mumbai
As you can the user_id column in Usermeta table refers the ID column from the User table.
I am in dire need of a MYSQL query which gives out the result in this manner -
ID user_email billing_phone billing_postcode billing_address
1 abc#gmail.com 9876443100 670001 Somewhere here, Delhi
2 abc#gmail.com 9876345188 650021 7th Lane, Bangalore
3 1sf#gmail.com 7852562100 400521 Fancy Area, Mumbai
I tried doing an UNION on two joins like this
SELECT 6ft_users.ID, 6ft_usermeta.meta_value as PHONE_NUMBER
FROM 6ft_users
INNER JOIN 6ft_usermeta
ON 6ft_users.ID=6ft_usermeta.user_id
WHERE 6ft_usermeta.meta_key LIKE 'billing_phone'
UNION
SELECT 6ft_users.ID, 6ft_usermeta.meta_value as POSTCODE
FROM 6ft_users
INNER JOIN 6ft_usermeta
ON 6ft_users.ID=6ft_usermeta.user_id
WHERE 6ft_usermeta.meta_key LIKE 'billing_postcode';
But this is not helping as I get only one column - PHONE_NUMBER. I tried a few other things but to no avail. Please help me out.
Thanks in advance!
Try this:
SELECT U.ID,
U.user_email,
MAX(IF(UM.meta_key = 'billing_phone', UM.meta_value, '')) AS billing_phone,
MAX(IF(UM.meta_key = 'billing_postcode', UM.meta_value, '')) AS billing_postcode,
MAX(IF(UM.meta_key = 'billing_address', UM.meta_value, '')) AS billing_address
FROM 6ft_users U
LEFT JOIN 6ft_usermeta UM ON U.ID = UM.user_id
GROUP BY U.ID
Trying to create a report across 3 tables - company, account, user. For each company, there's an ID in account. Each user has an account. I can get totals easily enough, but I need to add count of how many users out of the total are registered (username is not null).
SELECT c.c_name, c.c_groupnumber, count(a.a_userid) AS TotalCount
FROM company c
LEFT JOIN account a ON c.c_groupnumber = a.a_groupnumber
WHERE a.a_deleted IS NULL
GROUP BY c.c_groupnumber
HAVING TotalCount > 0;
How can I add in a condition that gives me a count of user.u_username not null while maintaining my TotalCount? The link between account and user is
a.a_userid = user.u_userid
tbl.company
c_id, c_groupnumber, c_name
1 1234 widgets, inc.
2 5678 joe's garage
tbl.user
u_userid, u_username, u_name
1 bill Bill Smith
2 frank Frank Johnson
3 NULL Jane Doe
4 mary Mary Stack
5 NULL Steve Spot
tbl.account
a_id, a_userid, a_groupnumber
100 1 1234
101 2 5678
102 3 5678
103 4 1234
104 5 1234
So using the above very simplified table example, company "Widget's Inc." has 3 employees (bill smith, mary stack and steve spot), and of those 3 2 have registered (bill and mary), while steve has not (username is null).
Joe's Garage has 2 employees - Frank and Jane, and Frank has registered, while Jane has not.
I'd love to generate a report something like this:
Group Company Total Emp Reg Emp
1234 Widgets Inc 3 2
5678 Joe's Garag 2 1
Hopefully that makes the question clearer?
What if you get the count of username and then perform a JOIN with that like
SELECT c.c_name, c.c_groupnumber, count(a.a_userid) AS TotalCount,
xxx.username_count
FROM company c
LEFT JOIN account a ON c.c_groupnumber = a.a_groupnumber
LEFT JOIN ( select u_userid, count(u_username) username_count
from `user`
group by u_userid ) xxx ON a.a_userid = xxx.u_userid
WHERE a.a_deleted IS NULL
GROUP BY c.c_groupnumber
HAVING TotalCount > 0;
I essentially like to have one query which I'll execute one time and like to have the result (no multiple query execution) and definitely, the query should use simple MySQL structure (no complex/advanced structure to be used like BEGIN, loop, cursor).
Say I've two tables.
1st Table = Country (id(PK), name);
2nd Table = Businessman (id(PK), name, city, country_id(FK))
Like to SELECT all countries, whose businessmen are from distinct cities. No two businessmen exist in one country, who are from the same city. If so, that country will not be selected by the SELECT clause.
Country
id name
1 India
2 China
3 Bahrain
4 Finland
5 Germany
6 France
Businessman
id name city country_id
1 BM1 Kolkata 1
2 BM2 Delhi 1
3 BM3 Mumbai 1
4 BM4 Beijing 2
5 BM5 Paris 6
6 BM6 Beijing 2
7 BM7 Forssa 4
8 BM8 Anqing 2
9 BM9 Berlin 5
10 BM10 Riffa 3
11 BM11 Nice 6
12 BM12 Helsinki 4
13 BM13 Bremen 5
14 BM14 Wiesbaden 5
15 BM15 Angers 6
16 BM16 Sitra 3
17 BM17 Adliya 3
18 BM18 Caen 6
19 BM19 Jinjiang 2
20 BM20 Tubli 3
21 BM21 Duisburg 5
22 BM22 Helsinki 4
23 BM23 Kaarina 4
24 BM24 Bonn 5
25 BM25 Kemi 4
In this respect, China and Finland shouldn't be listed.
I've attempted using count and group by, but no luck.
Can you please help me to build up this query.
Here it is, all you need is to join Businessman table and count cities and distinct cities and if they equal that means all businessmen are from different cities:
SELECT
c.`id`,
c.`name`,
COUNT(b.`id`) AS BusinessmanCount,
COUNT(b.`city`) AS CityCount,
COUNT(DISTINCT b.`city`) AS DistinctCityCount
FROM `countries` c
INNER JOIN Businessman b ON c.`id` = b.`country_id`
GROUP BY c.`id`
HAVING CityCount = DistinctCityCount
For minified version what you exactly need:
SELECT
c.`id`,
c.`name`
FROM `countries` c
INNER JOIN Businessman b ON c.`id` = b.`country_id`
GROUP BY c.`id`
HAVING COUNT(b.`city`) = COUNT(DISTINCT b.`city`)
Well, I think we should have waited for you to show your own query, because one learns best from mistakes and their explanations. However, now that you've got answers already:
Yes, you need group by and count. I'd group by cities to see if I got duplicates. Then select countries and exclude those that have duplicate cities.
select *
from country
where id not in
(
select country_id
from businessmen
group by city, country_id
having count(*) > 1
);
You need either nested aggregations:
select *
from Country
where id in
(
select country_id
from
(
select city, country_id,
count(*) as cnt -- get the number of rows per country/city
from Businessman
group by city, country_id
) as dt
group by country_id
having max(cnt) = 1 -- return only those countries where all counts are unique
)
Or compare two counts:
select *
from Country
where id in
(
select country_id
from Businessman
group by country_id
having count(*) = count(distinct city) -- number of cities is equal to umber of rows
)
name frnds city country job age
a aa dehradun india xyz 23
b bbb delhi india abc 23
c cc paris france sdc 45
d dd berlin germany der 19
e ee dehradun india dec 20
f ff delhi yog cdfr 43
suppose this is my table and I want to find out the city name and the country name where (both) are same.
result should be like this
name frnds city country job age
a aa dehradun india xyz 23
e ee dehradun india dec 20
One way is to group by city and country and find groups that have more than one member:
SELECT * FROM MyTable t
WHERE EXISTS(
SELECT city, country
FROM MyTable t2
WHERE t2.city = t1.city
AND t2.country = t1.country
GROUP BY city, country
HAVING COUNT(*) > 1
)
Here you calculate the list of duplicate city, country once, and join back to your original table.
You should consider create one composite index with city, country
SELECT A.*
FROM yourtable A
JOIN (SELECT city, country
FROM yourtable
GROUP BY city, country
HAVING COUNT(*) >= 2
) as duplicate
ON A.city = duplicate.city
AND A.country = duplicate.country
ORDER BY A.city, A.country;