Postgres - Выбрать элементы с user_id равным NULL, если строка с указанным user_id не существует - PullRequest
0 голосов
/ 09 июля 2020

У меня есть таблица item_metadata(item_id, item_name, user_id). Я сохраняю тот же item_id с настраиваемыми именами в зависимости от user_id, и я хотел бы иметь имя «по умолчанию», если пользовательское имя недоступно.

item_id | item_name       | user_id
001     | 'Default Name'  | NULL
001     | 'Custom Name'   | 100

Учитывая выше, я бы хотел, чтобы мой запрос возвращал 'Custom Name', если я передаю 100 как параметр user_id, но возвращал 'Default Name', если я передаю 101 как параметр user_id.

Я пробовал использовать COALESCE, UNION / INTERSECT / EXCEPT, но не могу получить желаемый результат.

Ответы [ 3 ]

0 голосов
/ 09 июля 2020

Я знаю, что это зачитывает ваш вопрос, поэтому, если он не соответствует вашей ситуации, сообщите об этом в комментариях, и я удалю его.

Я сталкивался с ситуациями, когда у элемента есть имя по умолчанию, но мы хотим показать индивидуальное имя для определенных пользователей.

Смоделировано следующим образом:

Схема (PostgreSQL v11)

create table item (
  id int primary key,
  default_name text
);

create table user_tab (
  id int primary key,
  user_name text
);

create table item_user_name_override (
  item_id int references item(id),
  user_id int references user_tab(id),
  custom_name text
);

insert into user_tab values (1, 'special_user'), (2, 'regular_guy');
insert into item values (1, 'Item 1'), (2, 'Item 2'), (3, 'Item 3');
insert into item_user_name_override values (1, 1, 'Special Name for Item 1');

Извлечь все пары пользователь / элемент

select u.user_name, i.id as item_id, 
       coalesce(no.custom_name, i.default_name) as item_name
  from user_tab u
 cross join item i
  left join item_user_name_override no 
   on no.item_id = i.id and no.user_id = u.id
 order by i.id, u.id 
;
| user_name    | item_id | item_name               |
| ------------ | ------- | ----------------------- |
| special_user | 1       | Special Name for Item 1 |
| regular_guy  | 1       | Item 1                  |
| special_user | 2       | Item 2                  |
| regular_guy  | 2       | Item 2                  |
| special_user | 3       | Item 3                  |
| regular_guy  | 3       | Item 3                  |

Просмотр на скрипте DB

0 голосов
/ 09 июля 2020

Если вы хотите это для одного элемента:

select t.*
from t
where item_id = '001'  and
      (user_id = 100 or user_id is null)
order by (user_id is not null)::int desc;

Если вы хотите это для всех элементов, используйте distinct on:

select distinct on (item_id) t.*
from t
where user_id = 100 or user_id is null
order by item_id, (user_id is not null)::int desc;
0 голосов
/ 09 июля 2020

Вы можете сделать это с помощью coalesce() следующим образом:

select coalesce(
  (select item_name from item_metadata where user_id = ?),
  (select item_name from item_metadata where user_id is null)
  ) item_name;

Замените ? на user_id, которое вы ищете.

См. демонстрацию .

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