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

Как написать оператор SQL (база данных MYSQL), который будет возвращать набор результатов, который уникален в сочетании с двумя столбцами?

Чтобы сделать мой вопрос максимально простым, допустим, у меня есть только две таблицы images и products. Я хочу запросить все изображения определенного набора продуктов, которые имеют в поле строку Swatch, images. Этот запрос успешно выполняется с использованием следующего SQL с использованием базы данных MYSQL:

SELECT 
    images.alt,
    images.product_id,
    images.src
FROM
    images
    INNER JOIN products
        ON products.product_id IN (
            "2112055640177",
            "2112056590449",
            "2112055378033",
            "2112062292081",
            "2112058490993",
            "2112062619761",
            "2112062488689",
            "2112066420849",
            "2112061833329",
            "2112052527217"
        )
WHERE 
    images.alt LIKE "%Swatch%";

Однако набор результатов полон дубликатов:

Black Tuscan - Swatch   2112049971313   foobar.com
Black Tuscan - Swatch   2112049971313   foobar.com
Black Tuscan - Swatch   2112049971313   foobar.com
Generic Black - Swatch  2112049971313   baz.com
Generic Black - Swatch  2112049971313   baz.com
Florence - Swatch   2112049971313   foobaz.com
Florence - Swatch   2112049971313   foobaz.com
Gold - Swatch   2112050593905   bazfoo.com
Gold - Swatch   2112050593905   bazfoo.com
Sand - Swatch   2112050593905   bazfoo.com
Sand - Swatch   2112050593905   bazfoo.com

Каждый набор изображений с идентификатором продукта имеет дубликаты (пример: Black Tuscan - Swatch 2112049971313 foobar.com, Black Tuscan - Swatch 2112049971313 foobar.com)

Мне бы хотелось, чтобы набор результатов не содержал дубликатов образцов товаров. Другими словами, изображения должны быть уникальными для images.alt и images.product_id. В идеале вместо указанного выше возвращаемого значения набор результатов должен выглядеть следующим образом:

Black Tuscan - Swatch   2112049971313   foobar.com
Generic Black - Swatch  2112049971313   baz.com
Florence - Swatch   2112049971313   foobaz.com
Gold - Swatch   2112050593905   bazfoo.com
Sand - Swatch   2112050593905   bazfoo.com
Black Tuscan - Swatch   1234586923813   foobar.com
Sand - Swatch   1234586923813   bazfoo.com

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

Я провел много поисков и нашел эти SO сообщения ( один , два и три ). Они предложили комбинации SQL, которые используют LEFT JOIN, или GROUP BY, или DISTINCT, но мне не удалось найти правильный оператор SQL, который дает мне уникальность, которую я ищу - уникальную для images.alt и images.product_id.

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Ваше объединение испорчено, потому что оно никак не связано между собой. Я думаю, что вам нужно что-то вроде этого:

SELECT images.alt, images.product_id, images.src
FROM images
INNER JOIN products
ON products.product_id = images.product_id
WHERE products.product_id IN ("2112055640177","2112056590449","2112055378033","2112062292081","2112058490993","2112062619761","2112062488689","2112066420849","2112061833329","2112052527217") and
images.alt LIKE "%Swatch%";

Относительно того, почему появились дубликаты, это называется декартовым произведением. Когда условия объединения нарушаются, строки, не связанные друг с другом, в итоге объединяются.

Если у вас было 2 товара и 3 изображения, и вы сделали:

products JOIN images ON 1=1

Условие соединения всегда выполняется, каждое изображение дублируется 2 раза, каждый продукт появляется 3 раза

P1,i1
P1,i2
P1,i3
P2,i1
P2,i2
P2,i3

Может помочь вам понять, что базы данных объединяют данные: они объединяют каждую строку в этой таблице с каждой строкой в ​​этой таблице, а затем удаляют объединенные строки, которые не соответствуют критериям в условии объединения

В исходном запросе, если в IN было 3 8 повреждения с «образцом» и 10 товаров, вы получаете 30 строк, так как каждая из 10 строк товара объединяется с каждым из 3 изображений. Если у вас было 100 продуктов и 100 изображений, представьте, что БД объединяет все комбинации, генерируя 10000 строк, а затем удаляет строки, не соответствующие IN (продукты 90/100 не допускаются, 90 процентов строк удаляются, удаляются 9000 строк, оставляя 1000), затем удалил все строки, не соответствующие WHERE (образы 97/100 не имеют образца, 97 процентов строк удалены, 970 строк удалены, осталось 30 строк)

Поскольку вы не выбрали все столбцы (SELECT *), вы не увидите вариантов, которые делают каждую строку уникальной ... вставьте ее, и вы увидите

Не используйте отчетливое удаление дубликатов, исправьте условие разорванного соединения, которое вызывает декартово произведение

0 голосов
/ 06 января 2019

Вам не нужно JOIN для продуктов вообще. Это может решить вашу проблему.

SELECT i.alt, i.product_id, i.src
FROM images i
WHERE i.product_id IN ('2112055640177', '2112056590449', '2112055378033', '2112062292081', '2112058490993', '2112062619761', '2112062488689', '2112066420849', '2112061833329', '2112052527217')
WHERE i.alt LIKE '%Swatch%';

Если это не решит вашу проблему, используйте GROUP BY:

SELECT i.alt, i.product_id, MAX(i.src)
FROM images i
WHERE i.product_id IN ('2112055640177', '2112056590449', '2112055378033', '2112062292081', '2112058490993', '2112062619761', '2112062488689', '2112066420849', '2112061833329', '2112052527217')
WHERE i.alt LIKE '%Swatch%'
GROUP BY i.alt, i.product_id;

Если вам действительно нужны дополнительные столбцы из products, вам нужно правильно сделать JOIN:

SELECT . . .
FROM images i JOIN
     products p
     USING (product_id)
WHERE p.product_id IN ('2112055640177', '2112056590449', '2112055378033', '2112062292081', '2112058490993', '2112062619761', '2112062488689', '2112066420849', '2112061833329', '2112052527217')
WHERE i.alt LIKE '%Swatch%';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...