Mysql query using IN with group_concat result - mysql

I'm trying to clean a db with duplicate records. I need to move the reference to a single record and delete the other one.
I have two tables: Promoters and Venues, each has a reference to a table called cities. The problem is that there are cities with the same name and different ids, that have a relation with venues and promoters.
With this query I can group all promoters and venues with a single city record:
SELECT c.id as id, c.name as name, GROUP_CONCAT( DISTINCT p.id ) as promoters_ids, GROUP_CONCAT( DISTINCT v.id ) as venues_ids
FROM cities as c
LEFT JOIN promoters as p ON p.city_id = c.id
LEFT JOIN venues as v ON v.city_id = c.id
WHERE c.name IN ( SELECT name from cities group by name having count(cities.name) > 1 )
GROUP BY c.name
Now I want to run an UPDATE query on promoters, setting the city_id equals to the result of the query above.
Something like this:
UPDATE promoters AS pr SET pr.city_id = (
SELECT ID
FROM (
SELECT c.id as id, c.name as name, GROUP_CONCAT( DISTINCT p.id ) as promoters_ids
FROM cities as c
LEFT JOIN promoters as p ON p.city_id = c.id
WHERE c.name IN ( SELECT name from cities group by name having count(cities.name) > 1 ) AND pr.id IN promoters_ids
GROUP BY c.name
) AS T1
)
How can I do this?
Thanks

If I understand correctly, you want to remove duplicate cities (in the end), so you need to update promoters that are linked to any of the cities you want to remove in that process.
I think it makes sense to use the lowest ID of any of the cities with the same name (could be the highest just as well, but I want to specify it at least, and don't leave it up to me.
So in order get the right ID for a promoter, I need to: Select the lowest ID of all cities that have the same name as the city already linked to a promoter.
Fortunately, that demand fits snuggly into a query:
UPDATE promoters AS pr
SET pr.city_id = (
SELECT
-- Select the lowest ID ..
Min(c.id)
FROM
-- .. of all cities ..
Cities c
-- .. that have the same name ..
INNER JOIN Cities pc on pc.Name = c.Name
WHERE
.. as the city already linked to the promoter being updated
pc.id = pr.city_id
GROUP BY
c.name)
The trick is to join Cities on itself by name, so you can easily get all cities with the same name. I think you tried the same with the IN clause, but that's a little more complex than it needs to be.
I don't think you need group_concat at all, besides checking if the inned query returns the correct cities indeed, although it doesn't make sense, since you're already grouping on the name. When written like this, you can tell that there should be no way that this can go wrong:
SELECT
-- Select the lowest ID ..
MIN(c.id) AS id,
GROUP_CONCAT(c.name) AS names --< already grouped by this, so why...
FROM
-- .. of all cities ..
Cities c
-- .. that have the same name.
INNER JOIN Cities pc on pc.Name = c.Name
GROUP BY
c.name
I hope I understood the question correctly.

Related

INNER JOIN mysql return nothing

I'm trying to get the city name for my drop down list but using INNER JOIN and mysql but I end up getting no result, Please help me identify the issue. Thanks so much in advance.
SELECT city_name
from cities
INNER JOIN states
ON cities.city_id = states.state_id
GROUP BY cities.city_name
and here is my cities table database
and here is my states table databse
Your query should be:
SELECT city_name
from cities
INNER JOIN states
ON cities.state_id = states.state_id
GROUP BY cities.city_name
You are matching city_id with State_Id which wouldn't fetch you anything

Mysql select query with count

I need to create a select query with count from another table.
I have two tables like category and candidates. Every candidate belong to one category.
Here I want to select all categories from category table along with how many candidates available for each category.
like this: category_name(23)
This is how I tried it. but it doesn't work for me.
SELECT c.category_id
, c.name
, COUNT(cn.job_category) AS cvs
FROM job_category c
LEFT JOIN candidates cn ON cn.job_category = c.category_id
ORDER BY c.name ASC
You are missing the group by clause.
SELECT c.category_id
, c.name
, COUNT(cn.job_category) AS cvs
FROM job_category c
LEFT JOIN candidates cn ON cn.job_category = c.category_id
GROUP BY c.category_id
, c.name
ORDER BY c.name ASC
Note: Without group by, mysql will just return an arbitrary category. It allows this behavior while most other database systems would result in an error when you don't include non-aggregated columns in the group by clause.

How can I build MySQL query with additional column equals to number of associated rows?

Let's say I have two tables Cities and Employees. Each employee associated with one city. How can I build a query resulting with all cities and will have additional column equals to number of employees associated with this city?
I tried the following:
SELECT *,COUNT(SELECT * FROM `Employees` WHERE `city_id` = `id`) AS `count` FROM `cities`
But it's not working.
Actually I have no idea where I should looking for. Hope that I will have any hint here.
You may try the following query using inner join between cities and employees table
SELECT cities.* ,COUNT( `Employees`.`id`) FROM `cities`
INNER JOIN `Employees` on `Employees`.`city_id` = `cities`.`id`
GROUP BY `cities`.`id`
If you prefer old style SQL you could try something like this
SELECT cityTable.`name`, employeesTable.employees_count
FROM (SELECT `id`, `name` FROM `Cities`)citiesTable,
(SELECT count(*) as employees_count, `city_id` FROM `Employees`)employeesTable
WHERE citiesTable.`id` = employeesTable.`city_id`
The predicate is: Give me all cities, and the number of employees belonging to them.
SELECT c.name, COUNT(e.id) cnt
FROM cities c
LEFT JOIN employees e
ON c.id = e.city_id
GROUP BY c.name
This will give you all cities with cnt zero if a city has no employees belonging to it

How can I find records using only certain rows in a joined table?

I have a DB with this layout...
contracts
---------
id
name
description
# Etc...
locations
---------
id
contract_id # FK to contracts.id
name
order_position
# Etc...
I need to find contracts by the name of their current location (and by other contracts columns at the same time).
The current location is the one with the greatest order_position.
In other words, I'm trying to write a query that will return rows from contracts based on location.name.
Ordinarily that would just be a simple join via location.contract_id and contracts.id.
For example, this would be the simple case, without the additional requirement...
SELECT c.*
FROM contracts c, locations l
WHERE
c.id = l.contract_id
AND
c.name LIKE '%bay%'
AND
l.name LIKE '%admin%';
But the additional requirement is that I want to narrow it down to the contract's location that has the greatest value for order_position.
Is there a way to do that with one query?
Something like this should work:
SELECT c.id,
c.name,
loc2.name,
loc2.order_position
FROM dbo.contracts c
INNER JOIN (
SELECT loc.contract_id,
MAX(loc.order_position) AS order_position
FROM locations loc
GROUP BY contract_id
) loc
ON c.id = loc.contract_id
LEFT JOIN dbo.locations loc2
ON loc2.contract_id = loc.contract_id
AND loc2.order_position = loc.order_position
Maybe
SELECT c.name FROM contracts c JOIN locations l ON c.id=l.contract_id
AND c.name IN(SELECT name FROM locations
WHERE locations.order_position IN(SELECT MAX(order_position) FROM locations GROUP BY locations.name))
I worked on it some more and found that this solves the problem...
SELECT c.*
FROM contracts c, locations l
WHERE
c.id = l.contract_id
AND
c.name LIKE '%bay%'
AND
l.name LIKE '%admin%'
AND l.order_position =
(
SELECT MAX(order_position)
FROM `locations`
WHERE `contract_id` = c.id
);

MySQL Join Query

I need to query the database by joining two tables. Here is what I have:
Table Town:
id
name
region
Table Supplier:
id
name
town_id
I currently have the following query which outputs all the Towns that belong to a given region:
SELECT id, name FROM Town WHERE region = 'North West';
Now I need to extend this query and create two further queries as follows:
Output the number of Suppliers for each Town
Output only the Towns that have 1 or more Supplier
I am using PHP for my scripts if that helps. I know I may be able to to get this data using PHP but in terms of performance it will probably be better if it is done in MySQL.
EDIT (27/07/10):
I now needs to extend this one last time - there is another table called Supplier_vehicles:
id
supplier_id
vehicle_id
A Supplier can have many Supplier_vehicles. The count (NumSupplier in this case) needs to now contain the total number of suppliers in a given town that have any of the given vehicle_id (IN condition):
SELECT * FROM Supplier s, Supplier_vehicles v WHERE s.id = v.supplier_id AND v.vehicle_id IN (1, 4, 6)
Need to integrate the above query into the existing JOIN query.
Count the number of suppliers.
SELECT t.id, t.name, count(s.id) as NumSupplier
FROM Town t
LEFT OUTER JOIN Suppliers s ON s.town_id = t.id
GROUP BY t.id, t.name
Only towns that have at least one supplier
SELECT DISTINCT t.id, t.name
FROM Town t
INNER JOIN Suppliers s ON s.town_id = t.id
And you are 100% correct, the best place for this is an SQL query.
SELECT t.id, t.name, count(s.id) as NumSupplier
FROM Town t
LEFT JOIN Suppliers s
[WHERE NumSupplier > 1]
GROUP BY t.id