Как создать уникальные комбинации 1-3 значений из одного столбца?(Заказ ТОЛЬКО не имеет значения) - PullRequest
1 голос
/ 07 июля 2019

У меня есть колонка мороженого вкусов.Я пытаюсь сгенерировать все возможные комбинации из 1-3 шариков мороженого.Ароматы могут повторяться.

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

Я пробовал:

SELECT DISTINCT Scoop1.Flavor, Scoop2.Flavor, Scoop3.Flavor
FROM icecream Scoop1, icecream Scoop2, icecream Scoop3
  • Проблема с вышеупомянутымчто он генерирует «повернутые» комбинации, где строки будут иметь одинаковую комбинацию из 3 совков, только в разных порядках.Поэтому к «шоколаду, клубнике, ванили» следует относиться так же, как к «клубнике, ванили, шоколаду», «ванили, шоколаду, клубнике» и т. Д.

А также пытались:

SELECT A.Flavor, B.Flavor, C.Flavor
FROM icecream A, icecream B, icecream C
WHERE A.Flavor != B.Flavor
AND A.Flavor != C.Flavor
AND B.Flavor != C.Flavor
  • Проблема с этим в том, что он не выводит никаких комбинаций, содержащих более одного и того же аромата (что не было неожиданностью, я просто пытался остановить вращение из первого примеранемного сократить результаты).

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


Я даже удаленно на правильном пути ...?Это домашнее задание, и я работаю над ним в течение нескольких часов, и теперь мой мозг кашляет.

Ответы [ 4 ]

3 голосов
/ 07 июля 2019

Вы можете добавить предложение where, чтобы исключить разные упорядочения и объединить разные номера совков с объединениями

SELECT Scoop1.Flavor, '<empty>', '<empty>'
FROM icecream Scoop1
UNION ALL
SELECT Scoop1.Flavor, Scoop2.Flavor, '<empty>'
FROM icecream Scoop1, icecream Scoop2
WHERE
    Scoop1.Flavor >= Scoop2.Flavor
UNION ALL
SELECT Scoop1.Flavor, Scoop2.Flavor, Scoop3.Flavor
FROM icecream Scoop1, icecream Scoop2, icecream Scoop3
WHERE
    Scoop1.Flavor >= Scoop2.Flavor AND Scoop2.Flavor >= Scoop3.Flavor
1 голос
/ 07 июля 2019

Никогда не используйте запятые в предложении FROM. Всегда используйте правильный, явный синтаксис JOIN.

Основная идея:

SELECT ic1.Flavor, ic2.Flavor, ic3.Flavor
FROM icecream ic1 CROSS JOIN
     icecream ic2 CROSS JOIN
     icecream ic3;

Однако, это не обеспечивает NULL совков. Для этого вам нужно ввести новую строку:

WITH ic as (
      SELECT flavor
      FROM icecream
      UNION ALL
      SELECT NULL
     )
SELECT ic1.Flavor, ic2.Flavor, ic3.Flavor
FROM icecream ic1 CROSS JOIN
     icecream ic2 CROSS JOIN
     icecream ic3
WHERE ic1.Flavor IS NOT NULL AND
      NOT (ic2.Flavor IS NOT NULL AND ic3.Flavor IS NULL);
0 голосов
/ 08 июля 2019

Давайте разберем проблему.

Начните с двух совков. Это действительно упрощает вещи, если вы добавляете строку со значением NULL:

with flavors(flavor) as (
select 'vanilla' from dual union all
select 'strawberry' from dual union all
select 'chocolate' from dual union all
select null from dual
)
select * from flavors a
join flavors b on a.flavor <= nvl(b.flavor, a.flavor)

FLAVOR       FLAVOR
chocolate    - 
chocolate   chocolate
chocolate   strawberry
chocolate   vanilla
strawberry   - 
strawberry  strawberry
strawberry  vanilla
vanilla     - 
vanilla     vanilla

Это работает из-за того, что Oracle обрабатывает NULL в сравнениях! Когда вы сравниваете NULL с чем угодно, даже с другим NULL, результат «неизвестен». Даже если вы сравниваете NULL с самим собой, результат никогда не бывает «верным». Итог: это условие гарантирует, что a.flavor не будет иметь значение NULL, что вам и нужно.

Теперь все, что нам нужно сделать, это добавить третий совок:

with flavors(flavor) as (
select 'vanilla' from dual union all
select 'strawberry' from dual union all
select 'chocolate' from dual union all
select null from dual
)
select * from flavors a
join flavors b on a.flavor <= nvl(b.flavor, a.flavor)
left join flavors c on b.flavor <= nvl(c.flavor, b.flavor);

Левое объединение гарантирует, что мы будем хранить строки там, где был только один совок.

0 голосов
/ 08 июля 2019

обновление 1

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

конец обновления 1

обновление 2

Я думаю, вы должны изучить возможность создания уникальных комбинаций с помощью рекурсивных cte Вот что я нашел по этой теме: Возврат всех возможных комбинаций значений в одном столбце в SQL

конец обновления 2

Простые перекрестные соединения с предложением where

with t as (
 select 1 as f
 union all select 2
 union all select null
 union all select 4
 )

 select distinct
  t.f,
  t1.f,
  t2.f
 from t
 cross join t t1
 cross join t t2
 where t1.f is not null
 order by t.f, t1.f, t2.f asc

** Схема (PostgreSQL v10.0)

| f   | f   | f   |
| --- | --- | --- |
| 1   | 1   | 1   |
| 1   | 1   | 2   |
| 1   | 1   | 4   |
| 1   | 1   |     |
| 1   | 2   | 1   |
| 1   | 2   | 2   |
| 1   | 2   | 4   |
| 1   | 2   |     |
| 1   | 4   | 1   |
| 1   | 4   | 2   |
| 1   | 4   | 4   |
| 1   | 4   |     |
| 2   | 1   | 1   |
| 2   | 1   | 2   |
| 2   | 1   | 4   |
| 2   | 1   |     |
| 2   | 2   | 1   |
| 2   | 2   | 2   |
| 2   | 2   | 4   |
| 2   | 2   |     |
| 2   | 4   | 1   |
| 2   | 4   | 2   |
| 2   | 4   | 4   |
| 2   | 4   |     |
| 4   | 1   | 1   |
| 4   | 1   | 2   |
| 4   | 1   | 4   |
| 4   | 1   |     |
| 4   | 2   | 1   |
| 4   | 2   | 2   |
| 4   | 2   | 4   |
| 4   | 2   |     |
| 4   | 4   | 1   |
| 4   | 4   | 2   |
| 4   | 4   | 4   |
| 4   | 4   |     |
|     | 1   | 1   |
|     | 1   | 2   |
|     | 1   | 4   |
|     | 1   |     |
|     | 2   | 1   |
|     | 2   | 2   |
|     | 2   | 4   |
|     | 2   |     |
|     | 4   | 1   |
|     | 4   | 2   |
|     | 4   | 4   |
|     | 4   |     |

Просмотр на БД Fiddle

...