Подтвердить что ты не робот

Подзапрос 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

Но когда он там, я не получаю ни одного из них. Я не понимаю, почему эта часть отфильтровывает и Джона. (Обратите внимание, что эти строки вообще не упрощаются). Только один из них для строк отфильтровывает Джона, но работает как ожидалось для Йозефа.

Что-то не так с моим кодом?

4b9b3361

Ответ 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