Как объединить несколько таблиц после внутреннего полного объединения?

#sql #postgresql

Вопрос:

В настоящее время у меня есть SQL, в котором я возвращаю таблицу с первым экземпляром каждой строки, которую я передаю каждый раз, и заказываю по цене продукта (самой дешевой) и если продукт есть на складе. Результатом также должен быть только один продукт только для каждого подобного продукта.

Так, например, в таблице ниже:

 name            | price | id | stock | detail_id
goat milk 1L    | 100   | 1  | 1     | uuu-1
normal milk     | 200   | 2  | 3     | uuu-2
dark chocolate  | 300   | 3  | 1     | uuu-3
normal chocolate| 100   | 4  | 55    | uuu-4
 

Я получу ответ:

 name            | price | id
goat milk 1L    | 100   | 1
normal chocolate| 100   | 4
 

Запрос, который я использовал для его создания, был таким:

 SELECT coalesce( t1."id", t2."id" ) as id,
           coalesce( t1."name", t2."name" ) as name,
           coalesce( t1."price", t2."price" ) as price
    FROM (
    SELECT id, name, price
    FROM public.product
    Where LOWER(name) like '% milk %' AND stock >0
    ORDER BY price
    LIMIT 1) t1
    FULL JOIN (
    SELECT id, name, price
    FROM public.product
    Where LOWER(name) like '% chocolate %' AND stock >0
    ORDER BY price
    LIMIT 1) t2
    ON t1."id" = t2."id"
 

Проблема в том, что в другой таблице у меня есть другой ключ, который называется allowed_to_use

 id_use | allowed_to_use
uuu-1  | true
uuu-2  | true
uuu-3  | true
uuu-4  | false
 

Как я могу присоединить эту таблицу к первой (присоединиться к id_use с помощью detail_id), чтобы иметь возможность показывать продукт, только если allowed_to_use это правда?

Желаемый результат был бы:

 name            | price | id
goat milk 1L    | 100   | 1
dark chocolate  | 300   | 3
 

Комментарии:

1. Как вы ожидаете справиться со сценарием, когда два молока или два шоколада имеют одинаковые низкие цены? Может быть, вы хотите вернуть их все, если все они имеют одинаковую самую низкую цену?

Ответ №1:

Одним из способов , которым вы могли бы это сделать, было бы exists включить detail_id в оба подзапроса и обернуть во внешний запрос, который затем проверяет, существует ли идентификатор и разрешено ли его использовать, что-то вроде:

 select
  Coalesce( t1."id", t2."id" ) as id,
  Coalesce( t1."name", t2."name" ) as name,
  Coalesce( t1."price", t2."price" ) as price
from
(
    select * from 
     (
        select id, name, price, detail_id
        from public.product
        where Lower(name) like '% milk %' and stock >0
        order by price
        Limit 1
    ) t1
    full join (
        select id, name, price, detail_id
        from public.product
        where Lower(name) like '% chocolate %' and stock >0
        order by price
        Limit 1
    ) t2 on t1."id" = t2."id"
)t
where exists (select * from allowed_to_use a where a.id_use=t.detail_id and a.allowed_to_use='true')
 

Комментарии:

1. Это приводит к ОШИБКЕ: отсутствует запись в предложении для таблицы «t1».

Ответ №2:

 SELECT coalesce( t1."id", t2."id" ) as id,
           coalesce( t1."name", t2."name" ) as name,
           coalesce( t1."price", t2."price" ) as price
    FROM (
    SELECT id, name, price
    FROM public.product
    Where LOWER(name) like '% milk %' AND stock >0
    ORDER BY price
    LIMIT 1) t1
    FULL JOIN (
    SELECT id, name, price
    FROM public.product
    Where LOWER(name) like '% chocolate %' AND stock >0
    ORDER BY price
    LIMIT 1) t2
    ON t1."id" = t2."id"
    LEFT JOIN allowed_to_use t11 ON t1.detail_id=t11.id_use
    LEFT JOIN allowed_to_use t12 ON t2.detail_id=t12.id_use
    WHERE coalesce(t11.allowed_to_use,t12.allowed_to_use);
 

Комментарии:

1. Я думаю, что это именно то, что мне нужно, единственный вопрос, который у меня остался, заключается в том, что вместо использования allowed_to_use = true, если бы я хотел выбрать ложные, что я должен изменить?

2. НЕ оператор — НЕ t11.alllowed_to_use

3. Это сработало идеально, спасибо, это решение. И последнее, если бы вы могли мне помочь, есть ли способ сделать его более «чистым», например, представьте, что если бы у меня было t1, t2…t20, мне пришлось бы сделать 20 левых соединений?

4. Вероятно, возьмите мой первый ответ и ВЫБЕРИТЕ ОТДЕЛЬНЫЙ … Я исправил свой первый пост, пожалуйста, проверьте его и дайте нам знать

Ответ №3:

Вы можете добавить более одного соединения в sql, но в вашем случае вам не нужно ваше первое соединение.

 SELECT DISTINCT name,price,id FROM product JOIN allowed_to_use ON detail_id=id_use WHERE (LOWER(name) like '% milk %' OR LOWER(name) like '% chocolate %') AND stock >0 AND allowed_to_use;
 

Предполагая, что все продукты представлены в 2 таблицах

Если нет, используйте ЛЕВОЕ СОЕДИНЕНИЕ и решите, что делать, если не определено значение allowed_to_use.

Комментарии:

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

2. Да, это так, я хочу просто вернуть в этом случае первые 2 появления результата. Если бы первые два, например, были молочными, я бы не стал отвечать на шоколад, как.

3. Хорошо, понял, поэтому вам нужно 2 раза присоединиться ко второй таблице, т. е. на t1 и t2 я пишу свое новое решение