it-swarm.com.ru

MySQL INNER JOIN выбрать только одну строку из второй таблицы

У меня есть таблица users и таблица payments, для каждого пользователя, у которых есть платежи, может быть несколько связанных платежей в таблице payments. Я хотел бы выбрать всех пользователей, у которых есть платежи, но выбрать только их последний платеж. Я пытаюсь этот SQL, но я никогда не пробовал вложенные операторы SQL раньше, поэтому я хочу знать, что я делаю неправильно. Ценим помощь

        SELECT u.* 
            FROM users AS u
            INNER JOIN (
                SELECT p.*
                FROM payments AS p
                ORDER BY date DESC
                LIMIT 1 )
            ON p.user_id = u.id
            WHERE u.package = 1
70
Wasim

Вы должны иметь подзапрос, чтобы получить их последнюю дату по user ID.

SELECT  a.*, c.*
FROM users a 
    INNER JOIN payments c
        ON a.id = c.user_ID
    INNER JOIN
    (
        SELECT user_ID, MAX(date) maxDate
        FROM payments
        GROUP BY user_ID
    ) b ON c.user_ID = b.user_ID AND
            c.date = b.maxDate
WHERE a.package = 1
105
John Woo
SELECT u.*, p.*, max(p.date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id
ORDER BY p.date DESC

Проверьте это sqlfiddle

10
Matei Mihai
SELECT u.*, p.*
FROM users AS u
INNER JOIN payments AS p ON p.id = (
    SELECT id
    FROM payments AS p2
    WHERE p2.user_id = u.id
    ORDER BY date DESC
    LIMIT 1
)

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

4
Finesse
   SELECT u.* 
        FROM users AS u
        INNER JOIN (
            SELECT p.*,
             @num := if(@id = user_id, @num + 1, 1) as row_number,
             @id := user_id as tmp
            FROM payments AS p,
                 (SELECT @num := 0) x,
                 (SELECT @id := 0) y
            ORDER BY p.user_id ASC, date DESC)
        ON (p.user_id = u.id) and (p.row_number=1)
        WHERE u.package = 1
3
valex

Ответ @John Woo помог мне решить аналогичную проблему. Я улучшил его ответ, установив правильный порядок. Это сработало для меня:

SELECT  a.*, c.*
FROM users a 
    INNER JOIN payments c
        ON a.id = c.user_ID
    INNER JOIN (
        SELECT user_ID, MAX(date) as maxDate FROM
        (
            SELECT user_ID, date
            FROM payments
            ORDER BY date DESC
        ) d
        GROUP BY user_ID
    ) b ON c.user_ID = b.user_ID AND
           c.date = b.maxDate
WHERE a.package = 1

Хотя я не уверен, насколько это эффективно.

1
GTCrais

Матей Михай дал простое и эффективное решение, но оно не будет работать до тех пор, пока MAX(date) не будет помещен в часть SELECT, поэтому этот запрос станет:

SELECT u.*, p.*, max(date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id

И порядок по не будет иметь никакого значения для группировки, но он может упорядочить конечный результат, предоставленный группой по. Я попробовал это, и это сработало для меня.

1
hassan

Есть две проблемы с вашим запросом:

  1. Каждой таблице и подзапросу нужно имя, поэтому вы должны назвать подзапрос INNER JOIN (SELECT ...) AS p ON ...
  2. Подзапрос, если он у вас есть, возвращает только один период строки, но вы на самом деле хотите одну строку для каждого пользователя . Для этого вам понадобится один запрос, чтобы получить максимальную дату, а затем самостоятельно присоединиться, чтобы получить всю строку.

Предполагая, что нет никаких связей для payments.date, попробуйте:

    SELECT u.*, p.* 
    FROM (
        SELECT MAX(p.date) AS date, p.user_id 
        FROM payments AS p
        GROUP BY p.user_id
    ) AS latestP
    INNER JOIN users AS u ON latestP.user_id = u.id
    INNER JOIN payments AS p ON p.user_id = u.id AND p.date = latestP.date
    WHERE u.package = 1
1
lc.

Мой ответ, вдохновленный @valex, очень полезен, если вам нужно несколько столбцов в предложении ORDER BY. 

    SELECT u.* 
    FROM users AS u
    INNER JOIN (
        SELECT p.*,
         @num := if(@id = user_id, @num + 1, 1) as row_number,
         @id := user_id as tmp
        FROM (SELECT * FROM payments ORDER BY p.user_id ASC, date DESC) AS p,
             (SELECT @num := 0) x,
             (SELECT @id := 0) y
        )
    ON (p.user_id = u.id) and (p.row_number=1)
    WHERE u.package = 1
0
Jérôme B