Помогите мне с этим полным внешним объединением (или объединением) MySql - PullRequest
0 голосов
/ 13 июня 2009

Это происходит из-за преобразования MSSQL в MySql. Вот код, который я пытаюсь заставить работать:

CREATE TEMPORARY TABLE PageIndex (
  IndexId int AUTO_INCREMENT NOT NULL PRIMARY KEY,
  ItemId VARCHAR(64)
);

INSERT INTO PageIndex (ItemId)
SELECT Paths.PathId
  FROM Paths,
       ((SELECT Paths.PathId
           FROM AllUsers, Paths
          WHERE Paths.ApplicationId = @ApplicationId
            AND AllUsers.PathId = Paths.PathId
            AND (@Path IS NULL
                OR Paths.LoweredPath LIKE LOWER(@Path))) AS SharedDataPerPath
          UNION -- This used to be a FULL OUTER JOIN but MySQL doesnt support that.
        (SELECT DISTINCT Paths.PathId
           FROM PerUser, Paths
          WHERE Paths.ApplicationId = @ApplicationId
            AND PerUser.PathId = Paths.PathId
            AND (@Path IS NULL
                OR Paths.LoweredPath LIKE LOWER(@Path))) AS UserDataPerPath
             ON SharedDataPerPath.PathId = UserDataPerPath.PathId)
          WHERE Paths.PathId = SharedDataPerPath.PathId OR Paths.PathId = UserDataPerPath.PathId
          ORDER BY Paths.Path ASC;

Предположим, что любые переменные уже существуют. Где это нарушение - в части «As SharedDataPerPath», так что я предполагаю, что я наложил псевдоним оператора select, чтобы вы могли получить к нему доступ, как к таблице, не поддерживается в MySQL? Если поможет схема таблицы, ответьте с комментарием, и я добавлю это к вопросу.

Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 13 июня 2009

A FULL OUTER JOIN часто можно смоделировать с помощью UNION как LEFT JOIN, так и RIGHT JOIN. то есть все это слева и те, что справа, по возможности совпадают по критериям объединения. По моему опыту, обычно это крайне редко используется. У меня есть большая система, где она используется только один раз.

То, что вы, похоже, хотите сделать здесь, потому что FULL OUTER JOIN недоступно, это UNION два набора и установка некоторых JOIN критериев между двумя подмножествами, что на самом деле невозможно. Два набора, UNION ed в вашем примере, не могут иметь псевдонимы, и при этом они не могут иметь предложение WHERE, которое пытается связать их.

1 голос
/ 18 июля 2012

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

  1. Поменяйте местами источники таблиц по столбцам, с которыми вы используете соединение, с одного выбора на другой, чтобы учесть значения NULL, созданные внешними объединениями.

  2. Добавьте функции COALESCE в ваши «фиксированные столбцы», которые также могут возвращаться в виде значений NULL, создаваемых внешними объединениями.

Пример:

SELECT
`Wins_VW`.`Year`,
`Wins_VW`.`Period`,
COALESCE(`Wins_VW`.`Wins`,0) as Wins,
COALESCE(`Leads_VW`.`Leads`,0) as Leads
FROM `Wins_VW` LEFT OUTER JOIN `Leads_VW`
ON( `Wins_VW`.`Year` = `Leads_VW`.`Year`
AND `Wins_VW`.`Period` = `Leads_VW`.`Period`)

UNION

SELECT
`Leads_VW`.`Year`,
`Leads_VW`.`Period`,
COALESCE(`Wins_VW`.`Wins`,0) as Wins,
COALESCE(`Leads_VW`.`Leads`,0) as Leads
FROM `Wins_VW` RIGHT OUTER JOIN `Leads_VW`
ON( `Wins_VW`.`Year` = `Leads_VW`.`Year`
AND `Wins_VW`.`Period` = `Leads_VW`.`Period`)
1 голос
/ 24 января 2011
-- Assuming these are defined in your store procedure
DECLARE @ApplicationId VARCHAR(64);
DECLARE @Path VARCHAR(256);
SET @ApplicationId = NULL;
Set @Path = NULL;

CREATE TEMPORARY TABLE SharedDataPerPath
(
  PathId VARCHAR(256)
);

CREATE TABLE UserDataPerPath
(
  PathId VARCHAR(256)
);

-- Do this instead of aliasing a select statment 'AS SharedDataPerPath'
INSERT INTO SharedDataPerPath
SELECT Paths.PathId
  FROM aspnet_PersonalizationAllUsers AllUsers, aspnet_Paths Paths
 WHERE Paths.ApplicationId = @ApplicationId
   AND AllUsers.PathId = Paths.PathId
   AND (@Path IS NULL OR Paths.LoweredPath LIKE LOWER(@Path));

-- Do this instead of aliasing a select statement 'AS UserDataPerPath'
INSERT INTO UserDataPerPath
SELECT DISTINCT Paths.PathId
  FROM aspnet_PersonalizationPerUser PerUser, aspnet_Paths Paths
 WHERE Paths.ApplicationId = @ApplicationId
   AND PerUser.PathId = Paths.PathId
   AND (@Path IS NULL OR Paths.LoweredPath LIKE LOWER(@Path));

-- This is how I would do my 'FULL OUTER JOIN'
SELECT Paths.PathId
    FROM `wppi_net_db`.`aspnet_Paths` Paths,
         (SELECT *
            FROM SharedDataPerPath AS s
            LEFT OUTER JOIN UserDataPerPath AS u
              ON s.PathID = u.PathID
           UNION -- OR UNION ALL see: http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/
          SELECT *
            FROM SharedDataPerPath AS s
           RIGHT OUTER JOIN UserDataPerPath AS u
              ON s.PathID = u.PathID) AS DataPerPaths
   WHERE Paths.PathId = DataPerPaths.PathId
   ORDER BY Paths.Path ASC;

-- At some point you need to drop your temp tables
DROP TEMPORARY TABLE SharedDataPerPath;
DROP TEMPORARY TABLE UserDataPerPath;
...