Как разработать схему, отобразить сообщение для ее владельца, но если владелец не указан, отобразить для всех пользователей? - PullRequest
0 голосов
/ 17 июня 2019

У меня есть такая схема,

message

+------------+----------+
| id         |  text    |
+------------+----------+
| 1          | message1 |
| 2          | message2 |
| 3          | message3 |
+------------+----------+

user_message

+------------+-------------+
| user_id    |  message_id |
+------------+-------------+
| 1          | 1           |
| 1          | 2           |
| 2          | 2           |
+------------+-------------+

, поскольку message3 не является владельцем, оно принадлежит всем пользователям.

Итак, у user1 есть message1, message2 и message3,

у user2 есть message2 и message3.

И мне нужно написать sql для запроса сообщений user1,

SELECT 
    *
FROM
    message AS a
        JOIN
    user_message AS b ON a.id = b.message_id AND b.user_id = 1 

UNION ALL 

SELECT 
    *
FROM
    message AS a
        LEFT JOIN
    user_message AS b ON a.id = b.message_id
WHERE
    b.user_id IS NULL

Правильно ли это оформление?

Или я должен добавить сообщение3 всем пользователям, как это?

+------------+-------------+
| user_id    |  message_id |
+------------+-------------+
| 1          | 1           |
| 1          | 2           |
| 2          | 2           |
| 1          | 3           |
| 2          | 3           |
+------------+-------------+

Но если у меня новый пользователь, я желаю новогособственное сообщение пользователя3, мне нужно написать дополнительный код для этого.

Как мне сделать это правильно?

РЕДАКТИРОВАТЬ:

Я сделалошибка выше, я проиграл дело, у одного пользователя может быть много сообщений.

Как подсказал Невилл Кайт.

Мне нравится "без сюрпризов".

И я изменяюимя столбца и схема для

сообщения

+------------+----------+
| id         |  text    |
+------------+----------+
| 1          | message1 |
| 2          | message2 |
| 3          | message3 |
+------------+----------+

user_message

+------------+-------------+-------------+
| id         |  user_id    |  message_id |
+------------+-------------+-------------+
| 1          |  1          |  1          |
| 2          |  1          |  2          |
| 3          |  2          |  2          |
| 4          |  null       |  3          |
+------------+-------------+-------------+

Теперь запрос будет

SELECT 
    *
FROM
    user_message AS a
        JOIN
    message AS b ON a.message_id = b.id
WHERE
    user_id = 1 OR user_id IS NULL;

Ответы [ 3 ]

0 голосов
/ 17 июня 2019

Вы можете использовать exists и not exists:

select m.*
from message m
where exists (select 1
              from user u
              where u.message_id = m.id and
                    u.user_id = 1
             ) or
      not exists (select 1
                  from user u
                  where u.message_id = m.id
                 );
0 голосов
/ 17 июня 2019

«Правильно» - сложная вещь, чтобы правильно понять схему. Я обычно предпочитаю подход «без сюрпризов» - кто-то должен иметь возможность понять, что происходит, взглянув на схему и данные, не читая документацию. Я также за «не повторяйся».

Вы предлагаете два варианта решения.

Первое решение содержит сюрприз - столбцы с именем «id» обычно являются первичным ключом таблицы; в этом случае столбец «id» на самом деле является внешним ключом таблицы «users». Чтобы уменьшить этот уровень неожиданности, я бы создал столбец «user_id», содержащий внешний ключ. Если «user_id» также является первичным ключом в вашем бизнес-домене, вы можете просто переименовать столбец.

Вторым сюрпризом является то, что столбец содержит данные внешнего ключа для пользовательской таблицы, которые не существуют, но вызывают специальное поведение - они отправляются всем пользователям. Менее удивительным решением было бы, чтобы это значение было «нулевым», а не несуществующим значением. Когда вы создаете пользователя 3, вы обновляете соответствующую запись в сообщении.

Ваша схема становится

сообщение

+----------------+----------+
|    id |user_id |  text    |
+-------+--------+----------+
| 1     |   1    | message1 |
| 2     |   2    | message2 |
| 3     | null   | message3 |
+-------+--------+----------+

Ваш второй вариант содержит еще один сюрприз - данные в «сообщениях» изменяются как побочный эффект изменения «пользователя» (при создании нового пользователя вам необходимо удалить все сообщения другим пользователям с идентификатором этот пользователь). Его преимущество в том, что оно явное - каждое сообщение / пользовательская комбинация сохраняется, но мне не нравится побочный эффект.

0 голосов
/ 17 июня 2019

Я бы предложил использовать CROSS JOIN для генерации этих "пропущенных" записей.
Поскольку ваш текущий запрос не сгенерирует эти пропущенные записи для всех пользователей

Что-то вроде

Запрос

SELECT 
 *
FROM 
 message
INNER JOIN
 user 
ON
 message.id = user.message_id

UNION ALL

SELECT 
 *
FROM 
 message 
CROSS JOIN
 user 
WHERE 
 message.id = (

  SELECT 
    message.id
  FROM 
    message
  LEFT JOIN 
    user
  ON
    message.id = user.message_id
  WHERE
    user.id IS NULL    
 )

Результат

| id  | text     | message_id |
| --- | -------- | ---------- |
| 1   | message1 | 1          |
| 2   | message2 | 2          |
| 1   | message3 | 1          |
| 2   | message3 | 2          |

см. демо

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