MySQL - Условные результаты запроса на основе значений полиморфных таблиц? - PullRequest
2 голосов
/ 21 мая 2019

У меня есть полиморфная таблица creationables, и я не могу определить ключевую часть для условного запроса, который возвращает все creationables на основе значения поля creationable_type (human или robot) на основе были ли они удалены из соответствующих таблиц (humans, robots и комбинированные robots и robot_upgrades). Вот 4 таблицы, за которыми следует псевдопросмотр:

1. creationables

| id | creationable_type | creationable_id | robot_upgrade_id | is_activated
----------------------------------------------------------------------------
| 1  |      human        |       1         |         0        |      1
| 2  |      robot        |       1         |         0        |      1
| 3  |      robot        |       2         |         1        |      1

2. люди

| id | name | deleted
---------------------
| 1  | Adam |  NULL

3. роботы

| id |  name   | deleted
------------------------
| 1  | Droid X |  NULL
| 2  | Droid Y |  NULL

4. robot_upgrades

| id |  upgrade_name   | deleted
--------------------------------
| 1  |    Patch V4     |  NOW()

Псевдопросмотр:

SELECT *
FROM creationables

 // If creationable_type == 'human'
 // we want to get non deleted humans
    JOIN humans ON humans.id=creationable_id WHERE humans.deleted=NULL

 // If creationable_type == 'robot' and robot_upgrade_id == '0'
 // we want to get non deleted robots
    JOIN robots ON robots.id=creationable_id WHERE robots.deleted=NULL

 // If creationable_type == 'robot' and robot_upgrade_id != '0'
 // we want to check both robots and robot_upgrades tables
 // and if either of them was deleted we do not want to return them
 // we want to get non deleted robots/robot_upgrades combo
    JOIN robots ON robots.id=creationable_id WHERE robots.deleted=NULL
    JOIN robot_upgrades ON robot_upgrades.id=robot_upgrade_id WHERE robot_upgrades.deleted=NULL

WHERE creationables.is_activated = '1'

Есть идеи, какой правильный условный запрос будет основан на комментариях к псевдопросу?

UPDATE Вот скрипка

Ожидаемый результат должен выглядеть следующим образом:

| id | creationable_type | creationable_id | robot_upgrade_id | is_activated
----------------------------------------------------------------------------
| 1  |      human        |       1         |         0        |      1
| 2  |      robot        |       1         |         0        |      1

creationables строка с идентификатором 3 не должна возвращаться, поскольку, хотя ее робот не удален из robots, связанный с ним robot_upgrade_id 1 удаляется в robot_upgrades.

1 Ответ

2 голосов
/ 21 мая 2019

Нет прямого способа сделать это.INNER JOINS исключит предыдущие типы сразу после первого JOIN, поэтому вы можете использовать LEFT JOINS, чтобы сделать что-то вроде этого:

SELECT *
FROM creationables A
    LEFT JOIN humans ON humans.id= A.creationable_id AND A.creationable_type = 'human' AND humans.deleted is NULL
    LEFT JOIN robots ON robots.id= A.creationable_id AND A.creationable_type = 'robot' AND robots.deleted is NULL
    LEFT JOIN robot_upgrades ON robot_upgrades.id=A.robot_upgrade_id AND A.creationable_type = 'robot' and robot_upgrade_id != '0' AND robot_upgrades.deleted is NULL
WHERE creationables.is_activated = '1';

ИЛИ вы можете попробовать подход UNION следующим образом:

SELECT * FROM creationables A JOIN humans ON humans.id= A.creationable_id AND A.creationable_type = 'human' AND humans.deleted is NULL
  UNION
SELECT * FROM creationables A JOIN robots ON robots.id= A.creationable_id AND A.creationable_type = 'robot' AND robots.deleted is NULL
  UNION
SELECT * FROM creationables A JOIN robot_upgrades ON robot_upgrades.id=A.robot_upgrade_id AND A.creationable_type = 'robot' and robot_upgrade_id != '0' AND robot_upgrades.deleted is NULL
WHERE creationables.is_activated = '1';

Если обновление робота удалено, оно также не должно возвращать робота, тогда вы можете использовать этот запрос вместо этого:

SELECT A.creationable_type, humans.name, null as "update" 
FROM creationables A 
JOIN humans ON humans.id= A.creationable_id AND A.creationable_type = 'human' AND humans.deleted is NULL
  UNION
SELECT A.creationable_type, robots.name, robot_upgrades.upgrade_name as "update"
FROM creationables A 
JOIN robots ON robots.id= A.creationable_id AND A.creationable_type = 'robot' AND robots.deleted is NULL
LEFT JOIN robot_upgrades ON robot_upgrades.id=A.robot_upgrade_id AND A.creationable_type = 'robot' and robot_upgrade_id != '0' AND robot_upgrades.deleted is NULL
WHERE A.is_activated = '1' AND robots.id NOT IN
(SELECT DISTINCT A.creationable_id FROM creationables A
JOIN robot_upgrades ON robot_upgrades.id=A.robot_upgrade_id AND A.creationable_type = 'robot' and robot_upgrade_id != '0' AND robot_upgrades.deleted is NOT NULL);

Возможно, это не лучший подход, но он сделает работу, надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...