Дублирование условия дает другой набор результатов

У меня есть следующий запрос:

SELECT *
FROM dp_organisation_member t82
WHERE (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, (
      SELECT GROUP_CONCAT(`Ids`)
      FROM (
         SELECT @Level := @Level + '1' `Level`, @Ids := (
            SELECT GROUP_CONCAT(`OrganisationId`)
            FROM dp_organisation
            WHERE FIND_IN_SET(`ParentId`, @Ids)
         ) `Ids`
         FROM (SELECT @Ids := '1', @Level := '0') temp1
         INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
      ) temp2
   ))
) AND (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, (
      SELECT GROUP_CONCAT(`Ids`)
      FROM (
         SELECT @Level := @Level+'1' `Level`, @Ids := (
            SELECT GROUP_CONCAT(`OrganisationId`)
            FROM dp_organisation
            WHERE FIND_IN_SET(`ParentId`, @Ids)
         ) `Ids`
         FROM (SELECT @Ids := '1', @Level := '0') temp1
         INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
      ) temp2
   ))
)

Как видите, два условия идентичны, поэтому, если я уберу одно из условий, запрос должен дать тот же результат. Однако запрос возвращает другой результат, когда присутствуют оба условия, чем при использовании только одного из них!

Внутренний запрос, используемый в условиях (ниже), в моем случае возвращает 115,131,153.

SELECT GROUP_CONCAT(`Ids`)
FROM (
   SELECT @Level := @Level+'1' `Level`, @Ids := (
      SELECT GROUP_CONCAT(`OrganisationId`)
      FROM dp_organisation
      WHERE FIND_IN_SET(`ParentId`, @Ids)
   ) `Ids`
   FROM (SELECT @Ids := '1', @Level := '0') temp1
   INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
) temp2

Когда используются оба условия, результат включает только строки, содержащие OrganisationId = 1. Когда используется только одно из условий, также включаются строки, в которых OrganisationId равно 115, 131 или 153.

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

SELECT *
FROM dp_organisation_member t82
WHERE (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, (
      SELECT GROUP_CONCAT(`Ids`)
      FROM (
         SELECT @Level := @Level + '1' `Level`, @Ids := (
            SELECT GROUP_CONCAT(`OrganisationId`)
            FROM dp_organisation
            WHERE FIND_IN_SET(`ParentId`, @Ids)
         ) `Ids`
         FROM (SELECT @Ids := '1', @Level := '0') temp1
         INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
      ) temp2
   ))
)

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

SELECT *
FROM dp_organisation_member t82
WHERE (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, "115,131,153")
) AND (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, (
      SELECT GROUP_CONCAT(`Ids`)
      FROM (
         SELECT @Level := @Level+'1' `Level`, @Ids := (
            SELECT GROUP_CONCAT(`OrganisationId`)
            FROM dp_organisation
            WHERE FIND_IN_SET(`ParentId`, @Ids)
         ) `Ids`
         FROM (SELECT @Ids := '1', @Level := '0') temp1
         INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
      ) temp2
   ))
)

Однако первый запрос в этом вопросе с повторяющимся условием не дает правильного результата.

Кто-нибудь может объяснить такое поведение?

Изменить

Я думаю, что это может быть проблема с MariaDB. Вот SQL Fiddle с MySQL, дающий правильный результат. Кажется, невозможно использовать MariaDB в SQL Fiddle. Есть ли другой простой способ проверить запросы в MariaDB?


person Magnar Myrtveit    schedule 19.10.2016    source источник


Ответы (1)


Похоже, это проблема с более новыми версиями MySQL и MariaDB.

Я испытываю проблему в этих базах данных:

  • MySQL 5.7.17
  • МарияДБ 10.1.25

Но он отлично работает в этих базах данных:

  • MySQL 5.6.35
  • MySQL 5.5.51

Чтобы проверить базу данных на наличие проблемы, выполните следующие запросы. Окончательный запрос должен вернуть 4 строки. Если он возвращает только одну строку, проблема затрагивает вашу версию базы данных.

CREATE TABLE `dp_organisation` (
  `OrganisationId` bigint(32) NOT NULL AUTO_INCREMENT,
  `ParentId` bigint(32) DEFAULT NULL,
  PRIMARY KEY (`OrganisationId`)
) ENGINE=MyISAM AUTO_INCREMENT=154 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `dp_organisation_member` (
  `OrganisationId` bigint(32) NOT NULL,
  `UserId` bigint(32) NOT NULL,
  PRIMARY KEY (`OrganisationId`,`UserId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `dp_organisation` VALUES (1,NULL),(2,NULL),(3,2),(115,1),(131,1),(153,115);

INSERT INTO `dp_organisation_member` VALUES (1,1),(2,2),(3,3),(115,4),(131,5),(153,6);


SELECT *
FROM dp_organisation_member t82
WHERE (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, (
      SELECT GROUP_CONCAT(`Ids`)
      FROM (
         SELECT @Level := @Level + '1' `Level`, @Ids := (
            SELECT GROUP_CONCAT(`OrganisationId`)
            FROM dp_organisation
            WHERE FIND_IN_SET(`ParentId`, @Ids)
         ) `Ids`
         FROM (SELECT @Ids := '1', @Level := '0') temp1
         INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
      ) temp2
   ))
) AND (
   t82.`OrganisationId` = '1' OR FIND_IN_SET(t82.`OrganisationId`, (
      SELECT GROUP_CONCAT(`Ids`)
      FROM (
         SELECT @Level := @Level+'1' `Level`, @Ids := (
            SELECT GROUP_CONCAT(`OrganisationId`)
            FROM dp_organisation
            WHERE FIND_IN_SET(`ParentId`, @Ids)
         ) `Ids`
         FROM (SELECT @Ids := '1', @Level := '0') temp1
         INNER JOIN dp_organisation ON NOT(ISNULL(@Ids))
      ) temp2
   ))
)

Изменить

Ошибка была подтверждена MySQL: https://bugs.mysql.com/bug.php?id=87339

Edit 2018-10-30 Вот скрипт для тестирования. Проблема также присутствует в MySQL 8.0.

https://www.db-fiddle.com/f/5SAJZJosQXMZsDmU1Lmi8X/0

person Magnar Myrtveit    schedule 02.08.2017