Вложенный запрос возвращает неправильное число строк

У меня в mysql запросе происходит что-то фантастическое. Вот мой запрос для вычисления себестоимости:

select inv.price_for_one
from invoice inv,
     posinfo pi,
     goods g,
     stock_item si,
     warehouses w
where g.id = :id
  and pi.id = w.pos_info_id
  and si.warehouses_id = w.id
  and g.id = si.goods_id
  and inv.stock_item_id = si.id
  and pi.client_legal_informations_id = 12
  and inv.id = (select max(inv_sub.id)
                from invoice inv_sub,
                     stock_item si_sub
                where inv_sub.id in (inv.id)
                  and inv_sub.warehouses_id = w.id
                  and inv_sub.archive = false
                  and inv_sub.expense = false
                  and inv_sub.stock_item_id = si_sub.id
                  group by inv_sub.id,
                  limit 1);

Непонятно почему он возвращает две строки, а должен возвращать только одну, это важное условие. Я выяснил, что подзапрос возвращает две строки, поэтому внешний запрос тоже возвращает два инвойса. Но почему внутренний запрос возвращает две строки?

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

select min(inv_sub.id)
from invoice inv_sub,
     stock_item si_sub
where inv_sub.id in (285, 286)
  and inv_sub.warehouses_id = 623
  and inv_sub.archive = false
  and inv_sub.expense = false
  and inv_sub.stock_item_id = si_sub.id
  group by inv_sub.id,
  limit 1;

И этот запрос вернул две строки. Что происходит, почему так?

Что-то не помогли советы. Вот такой запрос все равно возвращает две строки, а нужны данные по последней не списанной накладной

SELECT inv.price_for_one AS costPriceGoods
            FROM invoice inv,
                 posinfo pi,
                 goods g,
                 stock_item si,
                 warehouses w
            WHERE si.goods_id = g.id
              AND pi.client_legal_informations_id = 12
              AND w.pos_info_id = pi.id
              AND si.warehouses_id = w.id
              AND inv.stock_item_id = si.id
              AND inv.id = (SELECT DISTINCT inv_sub.id
                            FROM invoice inv_sub,
                                 stock_item si_sub
                            WHERE inv_sub.id in (inv.id)
                              AND inv_sub.warehouses_id = w.id
                              AND inv_sub.archive = FALSE
                              AND inv_sub.expense = FALSE
                              AND inv_sub.stock_item_id = si_sub.id
                            ORDER BY inv_sub.id
                            LIMIT 1)
              AND g.id = 10121
            ORDER BY inv.id;

Причем внутренний запрос возвращает одну строку

SELECT DISTINCT inv_sub.id
                            FROM invoice inv_sub,
                                 stock_item si_sub
                            WHERE inv_sub.id in (287, 288)
                              AND inv_sub.warehouses_id = 205
                              AND inv_sub.archive = FALSE
                              AND inv_sub.expense = FALSE
                              AND inv_sub.stock_item_id = si_sub.id
                            ORDER BY inv_sub.id
                            LIMIT 1

Ответы (1 шт):

Автор решения: AlexanderSt

Начнем с того, что такой запрос просто не выполнится - помешает запятая перед LIMIT 1. У Вас вернутся строки с inv_sub.id=285 и inv_sub.id=286, которые сгруппируются в 2 группы и в них посчитается min(inv_sub.id). Limit должен оставить от этих 2 строк первую (по мнению MySql), но тогда мне не очень ясен смысл этого действия. Ваш запрос можно преобразовать к виду:

select distinct inv_sub.id
from invoice inv_sub,
      stock_item si_sub
where inv_sub.id in (285, 286)
   and inv_sub.warehouses_id = 623
   and inv_sub.archive = false
   and inv_sub.expense = false
   and inv_sub.stock_item_id = si_sub.id
   order by inv_sub.id ASC
   limit 1;

вопрос только в том, что будет быстрее

Поправьте меня, если я ошибаюсь: в таблице invoice хранятся накладные, список не списанных накладных по складу 623 мы получим запросом

select inv_sub.id 
    from invoice inv_sub 
    where inv_sub.warehouses_id = 623  
      and inv_sub.archive = false  
      and inv_sub.expense = false;

последняя в этом списке будет max(inv_sub.id), которую и надо искать. Т.е. запрос надо преобразовать к виду

SELECT inv.price_for_one AS costPriceGoods
        FROM invoice inv,
             posinfo pi,
             goods g,
             stock_item si,
             warehouses w
        WHERE si.goods_id = g.id
          AND pi.client_legal_informations_id = 12
          AND w.pos_info_id = pi.id
          AND si.warehouses_id = w.id
          AND inv.stock_item_id = si.id
          AND inv.id = (SELECT max(inv_sub.id)
                        FROM invoice inv_sub,
                             stock_item si_sub
                        WHERE inv_sub.warehouses_id = w.id
                          AND inv_sub.archive = FALSE
                          AND inv_sub.expense = FALSE
                          AND inv_sub.stock_item_id = si_sub.id
                        )
          AND g.id = 10121
        ORDER BY inv.id;
→ Ссылка