I have 2 tables with the below structure where there is no relation of (PK / FK).
======== country =======
+----+-------+---------+
| id | name | visible |
+----+-------+---------+
| 1 | kkk | 0 |
| 2 | mmm | 1 |
| 3 | ttt | 1 |
| 4 | kkkkk | 0 |
+----+-------+---------+
============ city =============
+----+------+---------+-------+
| id | name | visible | c_id |
+----+------+---------+-------+
| 3 | k333 | 0 | 1 |
| 2 | k222 | 1 | 1 |
| 1 | kkk | 1 | 1 |
| 4 | k444 | 0 | 2 |
| 6 | k666 | 0 | 2 |
+----+------+---------+-------+
I am using country.id and city.country_id as the link between the 2 tables. I am trying to delete the countries and cities where visibility value is 0. After searching I came up with this piece of code:
delete country , city from country, city where city.country_id = country.id and country.id in (select id from country where visible = 0);
But it returns the below error:
ERROR 1093 (HY000): You can't specify target table 'country' for update in FROM clause
I tried to use JOIN with WHERE like this :
DELETE country , city
FROM country JOIN city
ON city.country_id = country.id
WHERE country.visible = 0
It worked well, but there is one more row which is having the value of 0 was not deleted.
======== Country ======
+----+-------+---------+
| id | name | visible |
+----+-------+---------+
| 2 | mmm | 1 |
| 3 | ttt | 1 |
| 4 | kkkkk | 0 |
+----+-------+---------+
#Mihai After I checked your code again I just added WHERE and it worked like this:
DELETE country, city
FROM country
LEFT JOIN city
ON city.country_id = country.id
WHERE country.visible = 0;
Use a JOIN with a WHERE, it is much clearer.
DELETE country , city
FROM country JOIN city
ON city.country_id = country.id
WHERE country.visible = 0
ON your sample data the kkk row with visible=0 wont be deleted since it has an id of 4 which doenst exist in the city table so it won`t be picked up in the join.
Related
I have a table like this (greatly simplified):
| id | firstName | lastName | parent |
|------------------------------------|
| 1 | NULL | Smith | NULL |
| 2 | John | NULL | 1 |
| 3 | Jack | NULL | 1 |
| 4 | Jimmi | Joe | 1 |
| 5 | Jane | Doe | NULL |
And I'm trying to create a query that can return the data like this:
| id | firstName | lastName |
|---------------------------|
| 1 | NULL | Smith |
| 2 | John | Smith |
| 3 | Jack | Smith |
| 4 | Jimmi | Joe |
| 5 | Jane | Doe |
Basically I want it to include all rows, including parent rows. In all child rows (where parent != NULL) I want it to pick the child field value, unless it it NULL, then it should pick the parent field value. Parent rows are not modified.
I've been trying different setups with different joins, but I can't get it right. Is this even possible?
Joining parent with id using the parent as the table 1, this is because if we put data_2.parent = data.id then it would have joined incorrectly and we would have 3 rows with id 1 instead of 1 row.
Once we have the join we just take the first non-null value using coalesce() . If the last name is present in the original table then we take that otherwise we use the new one that we create using the join above
code 1 :
WITH data_ AS (
SELECT data.*, data_2.last_name as new_last_name,
FROM [table name] as data
LEFT JOIN data_2
ON data.parent = data_2.id
)
SELECT
*,
COALESCE(data_.last_name,data_.new_last_name) AS final_name FROM data_
code 2: more direct
SELECT
data.id,
data.first_name,
COALESCE(data.last_name,data_2.new_last_name) as final_LAST NAME
FROM [table name] as data
LEFT JOIN data_2
ON data.parent = data_2.id
you can self join the table with an LEFT JOIN on parent and id
SELECT t1.`id`, t1.`firstName`, COALESCE(t1.`lastName`,t2.`lastName`) FROM table1 t1 LEFT JOIN table1 t2 ON t1.`parent` = t2.id
id | firstName | COALESCE(t1.`lastName`,t2.`lastName`)
-: | :-------- | :------------------------------------
1 | null | Smith
2 | John | Smith
3 | Jack | Smith
4 | Jimmi | Joe
5 | Jane | Doe
db<>fiddle here
These are the tables I am fetching count from
register
+----+-------------+--------+
| id | empSignupId | cityId |
+----+-------------+--------+
| 42 | 4 | 1 |
| 47 | 3 | 1 |
| 48 | 11 | 1 |
| 54 | 20 | 1 |
| 55 | 21 | 2 |
| 56 | 22 | 2 |
+----+-------------+--------+
guest_list
+-----+------------+-------------+
| id | guestName | empSignupId |
+-----+------------+-------------+
| 103 | Mallica SS | 3 |
| 104 | Kavya | 3 |
| 108 | Vinay BR | 11 |
| 109 | Akash MS | 11 |
+-----+------------+-------------+
cities
+----+---------------+
| id | cityName |
+----+---------------+
| 1 | Bengaluru |
| 2 | Chennai |
| 3 | Sydney |
| 4 | New York City |
| 5 | Shanghai |
| 6 | Chicago |
+----+---------------+
I need to fetch the count of people registered from particular city which includes people, their guests, if guests are not present also it should show the count of people.
This is what I tried
SELECT COUNT(gl.id) + COUNT(rfs.id), ct.cityName, rfs.cityId
FROM register rfs
INNER JOIN cities ct ON ct.id=rfs.cityId
INNER JOIN guest_list gl ON gl.empSignupId = rfs.empSignupId
GROUP BY rfs.cityId;
+-------------------------------+-----------+--------+
| COUNT(gl.id) + COUNT(rfs.id) | cityName | cityId |
+-------------------------------+-----------+--------+
| 8 | Bengaluru | 1 |
+-------------------------------+-----------+--------+
I also need the count of people from other cities to be displayed, since there are no guests from some cities its not returning that count.
Please help me figure this out, I am still new to MySQL.. any help is greatly appreciated.
You fist need to aggregate guest_list table in order to get the number of records per empSignupId:
SELECT empSignupId, COUNT(empSignupId) AS countGuest
FROM guest_list gl
GROUP BY empSignupId
Output:
empSignupId countGuest
----------------------
3 2
11 2
Now you have to use a LEFT JOIN to the derived table above in order to also get the number of records for each city:
SELECT COALESCE(SUM(countGuest), 0) + COUNT(rfs.id), ct.cityName, rfs.cityId
FROM register rfs
INNER JOIN cities ct ON ct.id=rfs.cityId
LEFT JOIN (
SELECT empSignupId, COUNT(empSignupId) AS countGuest
FROM guest_list gl
GROUP BY empSignupId
) gl ON gl.empSignupId = rfs.empSignupId
GROUP BY rfs.cityId;
Output:
COALESCE(SUM(countGuest), 0) + COUNT(rfs.id) cityName cityId
------------------------------------------------------------------
8 Bengaluru 1
2 Chennai 2
Using LEFT JOIN instead of INNER JOIN guarantees that we also get cities without guests.
Demo here
Note: If you also want to get cities without registrations then you need to place the cities table first and use a LEFT JOIN to register.
Use LEFT JOINS and add count(distinct r.empSignupId) + count(distinct g.id):
select
c.id as cityId,
c.cityName,
count(distinct r.empSignupId) + count(distinct g.id) as people_count
from cities c
left join register r on r.cityId = c.id
left join guest_list g on g.empSignupId = r.empSignupId
group by c.id;
The result would be:
| cityId | cityName | people_count |
|--------|---------------|--------------|
| 1 | Bengaluru | 8 |
| 2 | Chennai | 2 |
| 3 | Sydney | 0 |
| 4 | New York City | 0 |
| 5 | Shanghai | 0 |
| 6 | Chicago | 0 |
Demo: http://rextester.com/OTBH14189
If you don't need the rows with 0, change the first LEFT JOIN to an inner JOIN.
I have 2 tables like this.
Table : Family Members
----------------------------------
|Address | Name |
----------------------------------
|North Jakarta City | Andra |
|North Jakarta City | Halim |
|South Jakarta City | Irma |
|Thousand Island Village | Dian |
----------------------------------
Table : Member Details
---------------
| Name | Age |
---------------
| Andra | 1 |
| Halim | 50 |
| Irma | 20 |
| Dian | 4 |
---------------
What is the correct query if I want to count members between the ages 0 and 4 who live in a 'city'? I've tried using this query but the result is incorrect. The correct result should be 1 since only Andra who lives in a city and between the ages 0 and 4. Please help me.
SELECT COUNT(family_members.name) AS total FROM family_members, member_details
WHERE family_members.address LIKE '%City%' AND member_details.age BETWEEN 0 AND 4
You need a join
SELECT COUNT(fm.name) AS total
FROM family_members fm
Join member_details md on md.Name = fm.Name
WHERE fm.address LIKE '%City%' AND md.age BETWEEN 0 AND 4
with you syntax, you may add this in the where clause (because your query will generate a cartesian product).
BUT : you should really use the JOIN syntax
AND family_members.Name = member_details.Name
EDIT
By the way, I would strongly suggest to use surrogate keys in your tables (a name is not really something unique)
You should consider redesigning your database like:
----------------------------------
| user_id | Name | Age | city_id |
----------------------------------
| 1 | Andra | 1 | 1 |
| 2 | Halim | 50 | 1 |
| 3 | Irma | 20 | 1 |
| 4 | Dian | 4 | 2 |
----------------------------------
------------------------------------
|city_name | city_id |
------------------------------------
|North Jakarta City | 1 |
|Thousand Island Village | 2 |
------------------------------------
SELECT COUNT(*) AS total
FROM family_member
JOIN city on family_member.city_id = city.city_id
WHERE city.city_name= 'City' AND family_member.age BETWEEN 0 AND 4;
Also you should add indexes.
Good day!
Let's say I have two tables defined as follows:
TABLE USER(id, name, ...other fields that are unimportant)
| id | name |
-------------
| 1 | John |
| 2 | Mary |
| 3 | Luke |
| 4 | Lisa |
TABLE CHOICE(id, uid, kname) where uid is the foreign key to table USER.
Please note: I do NOT know how many distinct kname entries the table CHOICE has. The only thing I know is that they will be limited (say between 0 and 10).
| id | uid | kname |
---------------------
| 1 | 1 | city1 |
| 2 | 1 | city2 |
| 4 | 2 | city2 |
| 5 | 2 | city3 |
| 6 | 4 | city4 |
Is it possible to write a query which returns this table:
| id | name | city1 | city2 | city3 | city4 |
---------------------------------------------
| 1 | John | 1 | 1 | 0 | 0 |
| 2 | Mary | 0 | 1 | 1 | 0 |
| 3 | Luke | 0 | 0 | 0 | 0 |
| 4 | Lisa | 0 | 0 | 0 | 1 |
i. e. the table USER extended with as many additional columns as distinct kname in table CHOICE, labelled with kname and containing a 1 if there exist a row in CHOICE with uid equals to the user id and a zero otherwise.
Something like
SELECT u.id, u.name, (SELECT COUNT(c.uid) FROM CHOICE WHERE c.kname = 'city1') AS city1, (SELECT COUNT(c.uid) FROM CHOICE WHERE c.kname = 'city2') AS city2, (SELECT COUNT(c.uid) FROM CHOICE WHERE c.kname = 'city3') AS city4, (SELECT COUNT(c.uid) FROM CHOICE WHERE c.kname = 'city4') AS city4
FROM USER u
INNER JOIN CHOICE c ON u.id = c.uid
GROUP BY u.id, u.name
No need for subqueries. Usually you would just do
sum(kname = 'city1') as city1
, because the kname = 'city1' equals to true or false, 1 or 0. But you have to deal with possible null values, since you have to left join to get all entries from the users table, even the ones that do not have a corresponding entry in table choice. Therefor the use of the coalesce() function (it returns the first of its parameters, that isn't null).
select
u.id,
u.name,
sum(coalesce(kname, '') = 'city1') as city1,
sum(coalesce(kname, '') = 'city2') as city2,
sum(coalesce(kname, '') = 'city3') as city3,
sum(coalesce(kname, '') = 'city4') as city4
from user u
left join choice c on c.uid = u.id
group by u.id, u.name;
+------+------+-------+-------+-------+-------+
| id | name | city1 | city2 | city3 | city4 |
+------+------+-------+-------+-------+-------+
| 1 | John | 1 | 1 | 0 | 0 |
| 2 | Mary | 0 | 1 | 1 | 0 |
| 3 | Luke | 0 | 0 | 0 | 0 |
| 4 | Lisa | 0 | 0 | 0 | 1 |
+------+------+-------+-------+-------+-------+
Lets say I have the following tables:
Countries
---------------------------
| ID | Country Name |
---------------------------
| 1 | Greece |
| 2 | Italy |
| 3 | Spain |
---------------------------
Cities
---------------------------
| ID | City |
---------------------------
| 1 | Athens |
| 2 | Patra |
| 3 | Rome |
| 4 | Venice |
---------------------------
Countries & Cities
--------------------
| ID | Cntr | City |
--------------------
| 1 | 1 | 2 |
| 2 | 1 | 1 |
| 3 | 2 | 3 |
--------------------
Now, How can I run a MySQL query that will return the name of the countries and the total cities based on table "Countries & Cities" ?
In example to return:
---------------------------
| Cities | Country |
---------------------------
| 2 | Greece |
| 1 | Italy |
---------------------------
Try this out:
SELECT COUNT(cs.City) as Cities, cn.name as Country
FROM countries cn
INNER JOIN country_city cs ON cs.Cntr = cn.id
GROUP BY cn.name
OUTPUT:
2 | Greece
1 | Italy
There is only one JOIN is needed
SELECT `c`.`name`, COUNT(`c`.id)
FROM `countries_cities` AS `cc`
JOIN `countries` AS `c`
ON `c`.id = `cc`.country_id
GROUP BY `cc`.country_id
SELECT cn.Name, COUNT(*)
FROM CountriesAndCities cc
JOIN Countries cn ON (cn.ID = cc.Cntr)
GROUP BY cn.Name
You only need to group the countries in the countries & cities table:
SELECT COUNT(1), c.Name
FROM [countriesAndCities] cnc
INNER JOIN [country] c ON cnc.cnt = c.id
GROUP BY c.Name