ВИБЕРІТЬ * З декількох таблиць. MySQL


77

SELECT name, price, photo FROM drinks, drinks_photos WHERE drinks.id = drinks_id

yeilds 5 рядків (5 масивів), photoце єдине унікальне поле в рядку. name, priceповторити ( тут, fanta- name, price повторити 3 рази. ) Як мені позбутися цих дублікатів?

Редагувати: я хочу name, priceі все photoза кожен напій.

 id      name      price
  1.    fanta        5
  2.     dew         4


 id      photo                   drinks_id
  1.     ./images/fanta-1.jpg      1
  2.     ./images/fanta-2.jpg      1  
  3.     ./images/fanta-3.jpg      1 
  4.     ./images/dew-1.jpg        2
  5.     ./images/dew-2.jpg        2

5
Ну, у вас є 5 відповідних рядків, оскільки у вас є кілька рядків з однаковим напоєм_id. Що б ви очікували ? Яке фото ви хотіли б зберегти?
Джон Скіт,

Відповіді:


108

Те, що ви робите тут, називається a JOIN(хоча ви робите це неявно, оскільки ви вибираєте з кількох таблиць). Це означає, що якщо ви не поставили жодних умов у своєму реченні WHERE, у вас були всі комбінації цих таблиць. Лише за вашим станом ви обмежуєте приєднання до тих рядків, де відповідає ідентифікатор напою.

Але в результатах для кожного напою все-таки є X кілька рядків, якщо є X фотографії з цим конкретним напоєм_id. Ваше твердження не обмежує, які фотографії ви хочете мати!

Якщо вам потрібен лише один рядок на напій, вам слід сказати SQL, що ви хочете зробити, якщо є кілька рядків з певним ідентифікатором drink_id. Для цього вам потрібна групування та сукупна функція . Ви вказуєте SQL, які записи ви хочете згрупувати (наприклад, усі рівні напитки_id), і в SELECT потрібно сказати, який із різних записів для кожного згрупованого рядка результатів слід взяти. Для чисел це може бути середнім, мінімальним, максимальним (щоб назвати деякі).

У вашому випадку я не бачу сенсу запитувати фотографії щодо напоїв, якщо вам потрібен лише один рядок. Ви, напевно, думали, що у кожному випивці у вас може бути безліч фотографій , але SQL не може цього зробити. Якщо ви хочете лише будь-яку фотографію, і вам не важливо, яку ви отримаєте, просто згрупуйте за напитком_ідентифікатора (щоб отримати лише один рядок за напій):

SELECT name, price, photo
FROM drinks, drinks_photos
WHERE drinks.id = drinks_id 
GROUP BY drinks_id

name     price   photo
fanta    5       ./images/fanta-1.jpg
dew      4       ./images/dew-1.jpg

У MySQL ми також маємо GROUP_CONCAT , якщо ви хочете, щоб імена файлів були об’єднані в один рядок:

SELECT name, price, GROUP_CONCAT(photo, ',')
FROM drinks, drinks_photos
WHERE drinks.id = drinks_id 
GROUP BY drinks_id

name     price   photo
fanta    5       ./images/fanta-1.jpg,./images/fanta-2.jpg,./images/fanta-3.jpg
dew      4       ./images/dew-1.jpg,./images/dew-2.jpg

Однак це може стати небезпечним, якщо у вас є ,значення поля, оскільки, швидше за все, ви хочете розділити це ще раз на стороні клієнта. Це також не є стандартною сукупною функцією SQL.


Так, я хотів назву, ціну та безліч зображень для кожного напою.
NestedWeb

3
Якою мовою ви кодуєте програму, виконуючи ці запити? Оскільки MySQL не підтримує масиви як типи полів. Вам потрібно виконати кілька струнних трюків, як з, GROUP_CONCATі розділити його знову. Зазвичай це не робиться в реляційних базах даних. Ви повинні робити групування в програмі, а не в SQL (виявити повторювані ідентифікатори та побудувати ці масиви у вашій програмі).
leemes

@NestedWeb ласка, подивіться на stackoverflow.com/questions/9024248 / ...
leemes

@NestedWeb Якщо ви хочете всі зображення, краще (швидше) не використовувати GROUP BYі GROUP_CONTACT, а продовжувати, як ви робили, але впорядковувати drinks.id. Таким чином ви зможете перебирати набір результатів та збирати зображення в масиви на стороні клієнта.
bhovhannes

Це еквівалентно ВНУТРІШНЬОМУ ПРИЄДНАННЮ.
Славомір Ленарт

3

Тут ви знайдете повторювані значення для назви та ціни. Ідентифікатори повторюються в таблиці напоїв_фотографії. Ви ніяк не можете їх уникнути. А також, що саме ви хочете отримати?


2

Щоб позбутися дублікатів, ви можете згрупувати за drinks.id. Але таким чином ви отримаєте лише одну фотографію для кожної drinks.id(яка фотографія ви отримаєте, залежить від внутрішньої реалізації бази даних).

Хоча це не задокументовано, у випадку з MySQL ви отримаєте фотографію з найнижчою id(на моєму досвіді я ніколи не бачив іншої поведінки).

SELECT name, price, photo 
FROM drinks, drinks_photos 
WHERE drinks.id = drinks_id
GROUP BY drinks.id

1
Вам краще групуватися за ідентифікатором. Завжди групуйте за своїм унікальним полем, щоб отримати чіткі рядки вихідної таблиці. У вашому випадку, якщо два напої мають однакову назву (але мають різні рядки в таблиці), ви також згрупуєте їх разом.
leemes

дякую leemes, я не помітив, що існує унікальне поле ідентифікатора. Я відредагував свою відповідь. Звичайно, використання id його краще. @ypercube, ти справді думаєш, що твій коментар додає щось звичайне для публікації?
bhovhannes

@bhovhannes: Ні, ти маєш рацію, вибач. Коментарні коментарі не додають нічого корисного. Виправлена ​​відповідь є кращою - хоча я все ще не погоджуюсь із цим використанням GROUP BY(що не є стандартом SQL) без пояснення, чому він працює і як він поверне напіввипадковий photoдля кожного напою. ( "Перший" у фразі "ви отримаєте перше фото" просто неправильний).
ypercubeᵀᴹ

@ypercube, так, використання GROUP BY для фільтрації рядків (наприклад, у цій ситуації) не є стандартом SQL. Але це, безумовно, працює для MySQL, швидко, і повертається photoз найнижчим ідентифікатором. Я ніколи не бачив іншої поведінки в MySQL (хоча це не задокументовано). Я додав примітку до свого допису
bhovhannes
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.