Как использовать подзапрос с группой в MySQL? - PullRequest
1 голос
/ 12 октября 2019

У меня есть одна таблица с несколькими строками для конкретных пользователей. У меня есть данные за многие годы, например 2019,2018,2016 и более. У меня есть два сценария:

1. Я хочу данные конкретного INVOICE_YEAR.

2, но в то же время я хочу ПЕРВУЮ ДАТУ СЧЕТА, СОЗДАННУЮ ДЛЯ ОСОБЕННОГО ПОЛЬЗОВАТЕЛЯ.

мой SQL-запрос:

$yearOf это динамическая годовая переменная ввода.

$yearOf = 2019;

$Records = "SELECT MIN(inv.INVOICE_DATE) AS MIN_INVOICE_DATE
                    FROM invoices as inv
                    LEFT JOIN customers as cm ON cm.CUSTOMER_ID = inv.CUSTOMER_ID 
                    where inv.INVOICE_YEAR IN (".$yearOf.")
                    group by inv.CUSTOMER_ID ORDER BY cm.CUSTOMER_NAME ASC";

Как вы можете видеть мой запрос, если я хочу получить данные всех пользователей, у которых INVOICE_YEAR IN ('2019'). Мое первое условие будет удовлетворено, яполучит все данные пользователей, у которых INVOICE_YEAR = 2019.

Но в то же время я хочу указать дату первого счета, поэтому для этого я использовал MIN(inv.INVOICE_DATE), но, как я использовал
where inv.INVOICE_YEAR IN (".$yearOf."), это в тех условиях, где это даетмне первая дата счета определенного года.

Но я хочу первую дату счета из всей таблицы для всех пользователей.

Я пробовал с подзапросом, но он показывает мне ошибку Подзапрос возвращает больше, чем1 строка

Мой запрос с подзапросом:

$Records = "SELECT 
                    (
                    SELECT MIN(inv.INVOICE_DATE) AS MIN_INVOICE_DATE FROM invoices AS inv GROUP BY inv.CUSTOMER_ID) AS MIN_INVOICE_DATE
                    FROM invoices as inv 
                    LEFT JOIN customers as cm ON cm.CUSTOMER_ID = inv.CUSTOMER_ID 
                    where inv.INVOICE_YEAR IN (".$yearOf.")
                    group by inv.CUSTOMER_ID ORDER BY cm.CUSTOMER_NAME ASC";

Например:

3 клиентов есть 101,102,103

данные в таблице похожи:

id | customer_id | invoice_date | invoice_year
1  | 101         | 2019-01-01   |  2019
2  | 101         | 2016-01-01   |  2016
3  | 101         | 2017-01-01   |  2017
4  | 101         | 2016-01-02   |  2016
5  | 102         | 2019-01-02   |  2019
6  | 103         | 2018-01-02   |  2018
7  | 103         | 2019-01-07   |  2019
8  | 102         | 2015-01-02   |  2015

По мере того как я запрашиваю запрос для получения данных INVOICE_YEAR 2019 с первой датой выставления счетаконкретный пользователь, поэтому он должен выдать вывод, например:

id | customer_id | invoice_date | invoice_year | min_invoice_date
1  | 101         | 2019-01-01   |  2019        | 2016-01-01
5  | 102         | 2019-01-02   |  2019        | 2015-01-02
7  | 103         | 2019-01-07   |  2019        | 2019-01-07  

С, как я хочу первая дата выставления счета В КОЛОННЕ MIN_INVOICE_DATE всех пользователей.

Но он показывает мне данные как:

id | customer_id | invoice_date | invoice_year | min_invoice_date
1  | 101         | 2019-01-01   |  2019        | 2019-01-01
5  | 102         | 2019-01-02   |  2019        | 2019-01-02
7  | 103         | 2019-01-07   |  2019        | 2019-01-07  

Ответы [ 2 ]

1 голос
/ 12 октября 2019

Вы хотите получить самый ранний счет-фактуру для каждого клиента в 2019 году вместе с датой их самого раннего счета-фактуры во всей таблице.

В MySQL 8.0 это можно решить с помощью оконных функций:

SELECT id, customer_id, invoice_date, invoice_year, min_invoice_date
FROM (
    SELECT 
        t.*,
        ROW_NUMBER() OVER(PARTITION BY customer_id, invoice_year ORDER BY invoice_date) rn,
        MIN(invoice_date) OVER(PARTITION BY customer_id) min_invoice_date
    FROM mytable t
) x
WHERE invoice_year = 2019 AND rn = 1

В более ранних версиях вы можете:

  • JOIN в таблице с запросом, который вычисляет общий минимум invoice_date на клиента
  • , использовать коррелированныйподзапрос с условием NOT EXISTS для фильтрации по самому раннему клиенту счета-фактуры в 2019

Запрос:

SELECT t.id, t.customer_id, t.invoice_date, t.invoice_year, m.min_invoice_date
FROM mytable t
INNER JOIN (
    SELECT customer_id, MIN(invoice_date) min_invoice_date 
    FROM mytable 
    GROUP BY customer_id
) m ON m.customer_id = t.customer_id
WHERE 
    t.invoice_year = 2019
    AND NOT EXISTS (
        SELECT 1 
        FROM mytable t1
        WHERE t1.invoice_year = 2019 
        AND t1.customer_id = t.customer_id
        AND t1.invoice_date < t.invoice_date
    )

В этой демонстрации на DB Fiddle , оба запроса возвращают:

| id  | customer_id | invoice_date | invoice_year | min_invoice_date |
| --- | ----------- | ------------ | ------------ | ---------------- |
| 1   | 101         | 2019-01-01   | 2019         | 2016-01-01       |
| 5   | 102         | 2019-01-02   | 2019         | 2015-01-02       |
| 7   | 103         | 2019-01-07   | 2019         | 2018-01-02       |
0 голосов
/ 12 октября 2019

I угадайте вы хотите увидеть детали первого (самого раннего) счета для каждого клиента в каждом календарном году. Вы хотите, чтобы этот фильтрованный результат охватывал только один год.

Итак, начните с подзапроса, чтобы найти дату первого счета для каждого клиента в каждом календарном году. (https://www.db -fiddle.com / f / bmBZ14Vr9Re6ahpfs2FF2X / 0 )

      SELECT MIN(invoice_date) first_invoice_date,
             YEAR(invoice_date) calendar_year,
             customer_id
        FROM invoices
       GROUP BY YEAR(invoice_date), customer_id

Затем получите сведения об этих счетах, присоединив этот подзапрос к исходной таблице invoices. (https://www.db -fiddle.com / f / bmBZ14Vr9Re6ahpfs2FF2X / 1 )

SELECT invoices.*
  FROM invoices
  JOIN (
          SELECT MIN(invoice_date) first_invoice_date,
                 YEAR(invoice_date) calendar_year,
                 customer_id
            FROM invoices
           GROUP BY YEAR(invoice_date), customer_id
       ) firsts 
           ON invoices.customer_id = firsts.customer_id
          AND invoices.invoice_date = firsts.first_invoice_date
  ORDER BY invoices.customer_id, 
           invoices.invoice_year, 
           invoices.invoice_date

Затем добавьте WHERE invoices.invoice_year = 2019, чтобы получить год, который вы хотите.

Обратите внимание, что ваш столбец invoice_year не нужен, так как он всегда может быть вычислен из YEAR(invoice_date). Вы должны рассмотреть возможность избавиться от него.

...