Подзапрос MySQL WHERE слишком сильно отфильтровывается
Более короткая версия:
SQLfiddle
Проверьте выходной столбец lives_together
. Я хочу, чтобы он содержал объединенные (разделенные запятыми) идентификаторы членов, которые живут по тому же адресу, что и текущий член, но не являются родителем или ребенком для него/нее.
Итак, в первой строке, Джон, я хочу идентификатор Мэри (только).
Не Йозеф, так как он - сын Джона, а не Виктория, так как она живет по другому адресу (и она тоже его ребенок).
Сейчас я ничего не получаю, так или иначе это из-за этих строк в запросе (в третьем подзапросе):
mem.id <> m3.parent1 AND
mem.id <> m3.parent2 AND
mem.parent1 <> m3.id AND
mem.parent2 <> m3.id AND
Они должны отфильтровывать всех родителей и детей (что они делают), но по какой-то причине они также отфильтровывают и других членов (Мэри в приведенном выше примере).
Только один этих строк достаточно, чтобы отфильтровать Мэри.
Другим примером является Матс и Габриэлла, они должны получать друг от друга, но они этого не делают.
(Один столбец со всеми людьми living_together
(включая детей) недостаточно, так как я хочу напечатать лиц living_together
перед детьми. Этот вопрос является развитием этот другой вопрос Я спросил некоторое время назад. Одна большая разница в результате, который я хочу, состоит в том, что он никогда не должен группировать людей с разными именами.)
Почему это происходит?
Более длинная версия
У меня есть таблица, members
. Немного упрощенно это выглядит так (вы можете увидеть его целиком в SQLfiddle ниже):
+-------+------------+------------+------------+---------+----------+----------+-----------+-----------+---------------+
| id | first_name | last_name | birthdate | parent1 | parent2 | address | phones | mobiles | emails |
+-------+------------+------------+------------+---------+----------+----------+-----------+-----------+---------------+
| 2490 | Mary | Johansen | 1964-01-24 | NULL | NULL | Street 1 | 1111 | 9999,8888 | [email protected] |
| 2491 | John | Johansen | 1968-01-21 | NULL | NULL | Street 1 | 1111,3333 | 7777 | [email protected] |
| 2422 | Brad | Johansen | 1983-01-07 | 2491 | 2490 | Street 1 | 2222,3333 | 6666 | [email protected] |
| 2493 | Victoria | Andersen | 1982-01-14 | 2490 | 2491 | Av. 2 | 4444 | 5555 | [email protected] |
+-------+------------+------------+------------+---------+----------+----------+-----------+-----------+---------------+
Мэри и Джон женаты, с двумя детьми; Йозеф и Виктория.
Виктория ушла.
Я хочу напечатать список адресов, который группирует тех, кто живет по тому же адресу. Итак, Мэри, Джон и Йозеф должны сгруппироваться, но Виктория должна получить отдельную информацию.
Дети должны быть напечатаны после супругов (и любых других членов, проживающих по этому адресу), это причина их извлечения отдельно.
Вот как выглядит моя база данных и весь мой запрос:
http://sqlfiddle.com/#!2/1f87c4/2
это похоже на фактические данные, таблица содержит около 400 строк.
Итак, я хочу, чтобы столбец вывода lives_together
содержал group_concat
inated IDs совпадающих элементов. Поэтому я должен получить John id
в столбце Mary lives_together
, и наоборот. И не дети иды.
Я ожидаю что-то похожее на следующее.
Обратите внимание, что Брэд показан после Джона, несмотря на то, что у него как младший id, так и имя, начинающееся с буквы раньше в алфавите, это потому, что он ребенок в семье. Дети должны быть отсортированы по дате рождения (вы можете увидеть эту колонку в разделе "Также обратите внимание, что их номера телефонов добавляются вместе с их фамилией, но их мобильные номера (и электронные письма) помещаются с именами
+----------------------------------------------------
| Andersen Av 2 4444
| Victoria 5555 [email protected]
+----------------------------------------------------
| Johansen Street 1 1111,2222,3333
| John 7777 [email protected]
| Mary 9999,8888 [email protected]
| Brad 6666 [email protected]
+----------------------------------------------------
Это, однако, не то, что я ожидаю от запроса ниже, но моя цель после некоторой обработки PHP.
Это то, что я хочу из запроса:
+------+----------+-----------+------------+----------+-----------+-----------+---------------+-----------+-----------+----------------+
| id | lname | fname | birthdate | address | phones | mobiles | emails | parents | children | lives_together |
+------+----------+-----------+------------+----------+-----------+-----------+---------------+-----------+-----------+----------------+
| 2490 | Johansen | Mary | 1964-01-24 | Street 1 | 1111 | 9999,8888 | [email protected] | NULL | 2424 | 2491 |
+------+----------+-----------+------------+----------+-----------+-----------+---------------+-----------+-----------+----------------+
| 2491 | Johansen | John | 1968-01-21 | Street 1 | 1111,3333 | 7777 | [email protected] | NULL | 2424 | 2490 |
+------+----------+-----------+------------+----------+-----------+-----------+---------------+-----------+-----------+----------------+
| 2422 | Johansen | Brad | 1983-01-07 | Street 1 | 2222,3333 | 6666 | [email protected] | 2490,2491 | NULL | NULL |
+------+----------+-----------+------------+----------+-----------+-----------+---------------+-----------+-----------+----------------+
| 2493 | Andersen | Victoria | 1982-01-14 | Av. 2 | 4444 | 5555 | [email protected] | NULL | NULL | NULL |
+------+----------+-----------+------------+----------+-----------+-----------+---------------+-----------+-----------+----------------+
Здесь мой запрос (также несколько упрощен):
SELECT
mem.id as id,
mem.last_name as lname,
mem.first_name as fname,
mem.birthdate as birthdate,
mem.address as address,
mem.phones as phones,
mem.mobiles as mobiles
(SELECT
GROUP_CONCAT(m1.id)
FROM
members m1
WHERE
(mem.parent1 = m1.id OR mem.parent2 = m1.id) AND
LOWER(REPLACE(mem.last_name, ' ', '')) = LOWER(REPLACE(m1.last_name, ' ', '')) AND
LOWER(REPLACE(mem.address, ' ', '')) = LOWER(REPLACE(m1.address, ' ', '')) AND
mem.id <> m1.id
) as parents,
(SELECT
GROUP_CONCAT(m2.id)
FROM
members m2
WHERE
(mem.id = m2.parent1 OR mem.id = m2.parent2) AND
LOWER(REPLACE(mem.last_name, ' ', '')) = LOWER(REPLACE(m2.last_name, ' ', '')) AND
LOWER(REPLACE(mem.address, ' ', '')) = LOWER(REPLACE(m2.address, ' ', '')) AND
mem.id <> m2.id
) as children,
(SELECT
GROUP_CONCAT(m3.id)
FROM
members m3
WHERE
mem.id <> m3.parent1 AND
mem.id <> m3.parent2 AND
mem.parent1 <> m3.id AND
mem.parent2 <> m3.id AND
LOWER(REPLACE(mem.last_name, ' ', '')) = LOWER(REPLACE(m3.last_name, ' ', '')) AND
LOWER(REPLACE(mem.address, ' ', '')) = LOWER(REPLACE(m3.address, ' ', '')) AND
mem.id <> m3.id
) as lives_together
FROM
members mem
ORDER BY
mem.last_name ASC,
mem.first_name ASC
Когда запрос находится в Марии и проходит третий подзапрос (lives_together
), он должен получить Джона, но не Йозефа или Викторию.
Не Йозеф из-за mem.parent2 <> m3.id
, а не Виктория из-за LOWER(REPLACE(mem.address, ' ', '')) = LOWER(REPLACE(m3.address, ' ', ''))
.
Это работает, но по какой-то причине у Джона тоже нет, я просто получаю NULL
.
Я получаю как Джон, Йозеф, так и Викторию, если я удалю эту часть:
mem.id <> m3.parent1 AND
mem.id <> m3.parent2 AND
mem.parent1 <> m3.id AND
mem.parent2 <> m3.id AND
Но когда он там, я не получаю ни одного из них. Я не понимаю, почему эта часть отфильтровывает и Джона. (Обратите внимание, что эти строки вообще не упрощаются).
Только один из них для строк отфильтровывает Джона, но работает как ожидалось для Йозефа.
Что-то не так с моим кодом?
Ответы
Ответ 1
Я хочу напечатать список адресов, который группирует тех, кто живет по тому же адресу. Итак, Мэри, Джон и Йозеф должны сгруппироваться, но Виктория должна получить отдельную информацию.
Возможно, вы могли бы взглянуть на это по-другому, сосредоточившись на адресе? Например, этот результат:
| Members | street_address | postal_address | country |
|--------------------------------------------------|----------------|-------------------|---------|
| John Andersson, Mary Andersson, Josef Andersson | Street 1 | 61523 Stockholm | |
| Mats Anothername, Gabriella AnotherName | Betmsv.4 | 641 93 Stockholm | |
| Marie Coolname | Idrgatan 3 | 641 33 Stockholm | |
| Sofie Coolname | Torvgen 12 | 641 53 Stockholm | |
| Victoria Johnson | Avenue 3 | 61222 Stockholm | |
Производится по этому запросу:
SELECT
group_concat(DISTINCT concat( ' ',`first_name`, ' ',`last_name`)) as `Members`
, mem.`street_address`
, mem.`postal_address`
, mem.`country`
FROM `members` as mem
WHERE `member_type` = 1
GROUP BY
mem.`street_address`
, mem.`postal_address`
, mem.`country`
ORDER BY
max(`last_name`)
, `Members`
;
& с примером использования ORDER BY в GROUP_CONCAT
SELECT
group_concat(DISTINCT concat( ' ',`first_name`, ' ',`last_name`)
ORDER BY
case when `parent1` IS NULL and `parent2` IS NULL then 1 else 2 end
, `birth_date` ASC
) as `Members`
, mem.`street_address`
, mem.`postal_address`
, mem.`country`
FROM `members` as mem
WHERE `member_type` = 1
GROUP BY
mem.`street_address`
, mem.`postal_address`
, mem.`country`
ORDER BY
max(`last_name`)
, `Members`
;
Ответ 2
Я не уверен, что это то, что вы ищете, я подумал, что вам нужна одна запись для каждого адреса и для каждого списка адресов кто-то еще, кто живет по этому адресу.
SELECT distinct
mem.id as id,
mem.last_name as lname ,
mem.first_name as fname,
mem.birth_date as birthdate,
mem.phone_number as phone,
mem.mobile_number as mobile,
mem.email_address as email,
mem.co_address as co,
mem.street_address as street,
mem.postal_address as postal,
mem.country as country,
(SELECT
GROUP_CONCAT(m3.id)
FROM
members m3
WHERE
LOWER(REPLACE(mem.last_name, ' ', '')) = LOWER(REPLACE(m3.last_name, ' ', '')) AND
LOWER(REPLACE(mem.street_address, ' ', '')) = LOWER(REPLACE(m3.street_address, ' ', '')) AND
LOWER(REPLACE(mem.postal_address, ' ', '')) = LOWER(REPLACE(m3.postal_address, ' ', '')) AND
LOWER(REPLACE(mem.country, ' ', '')) = LOWER(REPLACE(m3.country, ' ', '')) AND
mem.id <> m3.id
AND m3.member_type = 1
) as lives_together
FROM
members mem
WHERE
member_type = 1
group by co_address,street_address,postal_address,country
ORDER BY
mem.last_name ASC,
mem.first_name ASC,
mem.birth_date DESC