Подзапрос возвращает более 1 строки в части SELECT (Dlookup to MySql) - PullRequest
0 голосов
/ 15 октября 2019

Я перевожу настольное приложение из MS Access VBA в приложение Java Springboot, и мне нужно, чтобы запрос VBA работал в MySQL. Запрос VBA безумно велик, поэтому я представляю вам небольшой пример, чтобы продемонстрировать мою ситуацию. Запрос VBA:

SELECT SELECT tbl_trade.id, 
   DLookUp("[price]","tbl_so_manifest","[so_id] = " 
   & tbl_trade.so_id & " AND [product_id] = " & tbl_po_manifest.product_id),
   // .... many more attributes....
FROM tbl_so_manifest as sm (((
   /// 15 nested INNER JOINS ....
   INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
   INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id
   )));

Преобразование MySQL:

SELECT SELECT tbl_trade.id, 
   (SELECT sm.product_id 
   FROM tbl_so_manifest as sm 
      INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
      INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id), 
   // ......
FROM tbl_so_manifest as sm (((
   /// 15 nested INNER JOINS ....
   INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
   INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id
   )));

, но выдает ошибку

Код ошибки: 1242. Подзапрос возвращает более 1 строки 0,844 с

Нужны предложения о том, как справиться с этим.

Ответы [ 3 ]

0 голосов
/ 15 октября 2019

Рассмотрите возможность удаления INNER JOIN с подзапроса, поскольку вы не делаете это в MS Access 'DLookUp (что интересно, вы не используете указанные псевдонимы в его логике критериев). Помните, что SELECT (по иронии судьбы первое предложение в списке) обычно является последним в порядке операций SQL, поэтому он может читать внешние столбцы, t.so_id и pm.product_id в подзапросе.

...
  (SELECT sm.`price`
   FROM tbl_so_manifest as sm 
   WHERE sm.so_id = t.so_id 
     AND sm.product_id = pm.product_id) AS sub_name 
...

Более эффективно использовать подзапрос в качестве производной таблицы (или CTE в MySQL 8) для объединения со всеми другими таблицами. Это позволяет избежать построчных вычислений и выполнить поиск один раз, чтобы присоединиться к полному набору результатов.

SELECT 
   sm.`price`,
   ...
FROM tbl_so_manifest as sm
/// 15 nested INNER JOINS ....
INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id
INNER JOIN (
    SELECT `so_id`, `product_id`, `price`
    FROM tbl_so_manifest
   ) sm
 ON sm.so_id = t.so_id 
 AND sm.product_id = pm.product_id;

Примечание: MySQL не требует скобок вокруг нескольких JOIN с (что, надеюсь, мое предложение MS однажды исправит в MS Access SQL).

0 голосов
/ 22 октября 2019

Вы можете ограничить подзапрос возвращением только одного reocrd, используя ключевое слово LIMIT 1. (ВЫБЕРИТЕ ЦЕНУ ОТ tbl_so_manifest ГДЕ so_ID = tbl_trade.so_id И product_id = sm.product_id ЗАКАЗАТЬ ПО ЦЕНЕ, ID DESC LIMIT LIMIT 1) КАК MyPrice

0 голосов
/ 15 октября 2019

Вы можете заставить подзапрос возвращать только один reocrd с вершиной 1

Так вот:

DLookUp("[price]","tbl_so_manifest","[so_id] = " 
& tbl_trade.so_id & " AND [product_id] = " & tbl_po_manifest.product_id)

Становится:

(SELECT TOP 1 Price FROM tbl_so_manifest 
         WHERE so_ID = tbl_trade.so_id AND product_id = sm.product_id
         ORDER BY PRICE, ID DESC) AS MyPrice

Так что вы на самом делене нужно объединение, а просто "выдерни" значение. Чтобы ограничить подзапрос ОДНОЙ записью, ТОП 1 и порядок по "PK" обеспечат возвращение только одной строки. Если вы пропустите «id», то, если две верхние цены будут одинаковыми, вы получите две строки. Добавив «ID» к заказу, вы получите только одну строку, даже если 5 цен одинаковы.

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

Таким образом, как правило, вы можете заменить dlookup () запросом вышеупомянутого типа. Я не очень хорошо знаком с MySQL, поэтому вы не сможете использовать псевдоним таблицы, как указано выше, но в целом используйте топ 1 и порядок с "ID (или PK), добавленным после цены или что-то еще в этих случаях. где может существовать более одной строки. В большинстве случаев у dlookup () не должно быть нескольких значений (но dlookup () всегда возвращает только одно значение). Так что в большинстве случаев «переводит» из dlookup () в подзапрос,top 1 не должен быть обязательным.

И я не могу думать, что dlookup () нуждается в "join". Dlookup () всегда попадает в одну таблицу, как и при преобразовании dlookup () в subзапрос. Вы хотите, чтобы столбец собирал, таблицу, а затем критерии).

Если dlookup () является значением FK, то левое соединение с таблицей поиска легче, и не приведет к появлению лишних строк взапрос, но любой подход в порядке. Я обнаружил, что у подзапроса меньше шансов "связываться" с основным числом запросов, возвращаемых строк.

Итак, dlookup () для подзапроса являетсяпреобразование один в один. Соединение не требуетсяed, и, как отмечалось в большинстве случаев, TOP + + добавленный id / pk не требуется в большинстве случаев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...