ЛІВО ПРИЄДНАЙТЕСЬ тільки перший ряд


138

Я читав багато тем про отримання лише першого ряду лівого з'єднання, але, чомусь, це не працює для мене.

Ось моя структура (спрощена звичайно)

Канали

id |  title | content
----------------------
1  | Feed 1 | ...

Художники

artist_id | artist_name
-----------------------
1         | Artist 1
2         | Artist 2

feed_artists

rel_id | artist_id | feed_id
----------------------------
1      |     1     |    1 
2      |     2     |    1 
...

Тепер я хочу отримати статті та приєднатись лише до першого виконавця, і я придумав щось подібне:

SELECT *
    FROM feeds 
    LEFT JOIN feeds_artists ON wp_feeds.id = (
        SELECT feeds_artists.feed_id FROM feeds_artists
        WHERE feeds_artists.feed_id = feeds.id 
    LIMIT 1
    )
WHERE feeds.id = '13815'

просто отримати лише перший рядок каналів_artists, але це вже не працює.

Я не можу використовувати TOPчерез свою базу даних і не можу групувати результати за тим, feeds_artists.artist_idяк мені потрібно сортувати їх за датою (я отримав результати, групуючи їх таким чином, але результати там, де не новітні)

Спробував щось із зовнішньою заявкою - також успіху теж немає. Якщо чесно, я не можу реально уявити, що відбувається в цих рядках - напевно, найбільша причина, чому я не можу це зробити.

РІШЕННЯ:

SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
    SELECT artist_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.id
    LIMIT 1
)
WHERE f.id = '13815'



Ви повинні поставити рішення як відповідь, щоб ми могли його проголосувати, і воно буде більш помітним для майбутніх відвідувачів
fguillen

Я думаю, ти маєш рацію - я також додав це як відповідь.
KddC

Відповіді:


97

Якщо ви можете припустити, що ідентифікатори виконавця збільшуватимуться в часі, тоді це MIN(artist_id)буде найшвидшим.

Тож спробуйте щось подібне (неперевірене ...)

SELECT *
  FROM feeds f
  LEFT JOIN artists a ON a.artist_id = (
    SELECT
      MIN(fa.artist_id) a_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.feed_id
  ) a

Дякуємо за вашу швидку відповідь. Це була не точна відповідь, але цілком перевела мене в правильний шлях. Я завжди намагався приєднатися до обох на одному рівні замість того, щоб один залежав від іншого. Дуже дякую, що повели мене на правильний шлях. Редагував першу публікацію
KddC

4
Хіба в цей момент простий підзапит не буде кращим? Тому що тепер у вас є приєднання та підзапит. Просто запитую причину, я шукаю рішення тієї самої проблеми :)
galdikas

2
підзапит занадто повільний.
Sinux

1
@Sinux визначте "занадто повільно". Це залежить від кількості записів і від заданих вимог.
спостерігач

1
Це не вийде! Підзапит не дозволяє передавати поле з батьківського запиту !!!
Thh Sinh

53

Версія без підселектора:

   SELECT f.title,
          f.content,
          MIN(a.artist_name) artist_name
     FROM feeds f
LEFT JOIN feeds_artists fa ON fa.feed_id = f.id
LEFT JOIN artists a ON fa.artist_id = a.artist_id
 GROUP BY f.id

2
я не думаю, що це буде перший рядок (перший ідентифікатор або перший щось інше), це просто випадковим чином вибрати один з лівих рядків приєднання.
Sinux

26
Цей запит неправильний. Він вибере найменше ім'я виконавця, а не ім'я перших виконавців у наборі.
Глапа

5
Неправильно для питання ... але саме того, що я хочу. У моєму випадку я просто хочу перше посвідчення з таблиці, до якої я приєднуюся.
Дрю Стівенс

2
Проблема тут полягає в тому, що якщо ви вирішите зробити COUNT або SUM, у вас з’явилися дані. Проблема з Subselect полягає в тому, що важче отримати дані, оскільки він створив тимчасову таблицю ... Я хотів би, щоб MySql міг мати обмеження на рівні LEFT JOIN.
Shadoweb

У цьому рішенні є проблема ефективності. Замість цього використовуйте рішення Min / Max.
PM Sadegh PM

25

@Matt Dodges відповідь поставила мене на правильний шлях. Ще раз дякую за всі відповіді, які допомогли дуже багато хлопців у середній час. Зробив це так:

SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
    SELECT artist_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.id
    LIMIT 1
)
WHERE f.id = '13815'

Ця відповідь працює лише для першого ряду. Порушення, коли немає f.idстану.
Тажні

2

Я використав щось інше (я думаю, що краще ...) і хочу поділитися цим:

Я створив ВИГОТОВЛЕННЯ, яке містить пункт «груповий»

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

Я хочу ще сказати, що я думаю, що нам потрібно зробити це рішення, Оскільки ми ВИСТАВЛИЛИ НЕЩО НЕБЕЗПЕЧНО В АНАЛІЗІ ... принаймні в моєму випадку ... але іноді це дешевше зробити це, щоб все переробити ...

Я сподіваюся, що це допомагає!


Якщо припустити, що для кожного є кілька рядків (провінцій?) country_code, GROUP BYЦе неправильно. Див ONLY_FULL_GROUP_BY.
Рік Джеймс

Вам не потрібно створювати представлення, яке використовуватиметься виключно для ВЛІТІЧНОГО / ВНУТРІШНЬОГО ПРИЄДНАННЯ ?! Можна використовувати підзапит або WITH x AS (пункт?
kiradotee

2

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

конвертувати:

LEFT JOIN table2 t2 ON (t2.thing = t1.thing)

до:

LEFT JOIN table2 t2 ON (t2.p_key = (SELECT MIN(t2_.p_key) 
    FROM table2 t2_ WHERE (t2_.thing = t1.thing) LIMIT 1))

умова, що з'єднує t1 і t2, переміщується з ON внутрішнього запиту та у нього WHERE. MIN(primary key)або LIMIT 1гарантують , що тільки один рядок повертається внутрішнім запитом.

після вибору одного конкретного рядка нам потрібно сказати, ONякий це рядок. тому ONпорівняння первинного ключа об'єднаної таблиці.

Ви можете грати з внутрішнім запитом (тобто замовлення + ліміт), але він повинен повернути один первинний ключ потрібного рядка, який підкаже ONточний рядок для приєднання.


зауважує: він також працюватиме лише з одним LIMITабо лише з ним MIN. ONумова має бути на приєднується таблиці первинного ключа для зниження продуктивності уникнути.
oriadam

1

Я хочу дати більш узагальнену відповідь . Такий, який буде обробляти будь-який випадок, коли ви хочете вибрати лише перший елемент у лівому приєднанні .

Ви можете використовувати підзапит, що GROUP_CONCATS, що ви хочете (відсортовано теж!), А потім просто розділити результат GROUP_CONCAT і взяти лише його перший елемент, як-от так ...

LEFT JOIN Person ON Person.id = (
    SELECT SUBSTRING_INDEX(
        GROUP_CONCAT(FirstName ORDER BY FirstName DESC SEPARATOR "_" ), '_', 1)
    ) FROM Person
);

Оскільки у нас є DESC як наш варіант ЗАМОВЛЕННЯ , це поверне ідентифікатор особи для когось, як "Zack". Якби ми хотіли, щоб хтось з таким ім'ям, як "Andy", ми змінили ORDER BY FirstName DESC на ORDER BY FirstName ASC .

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

Однак це корисно для запуску звітів, що містять дані, для адміністратора.


GROUP_CONCATТрюк добре до тих пір , як число значень обмежена. Ліміт за замовчуванням - 1024 символи.
Рік Джеймс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.