帮我解决这个MySql全外连接(或联合)

时间:2009-06-13 01:38:44

标签: mysql union left-join inner-join outer-join

这是将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 个答案:

答案 0 :(得分:2)

FULL OUTER JOIN通常可以使用UNIONLEFT JOIN的{​​{1}}进行模拟。即它全部在左侧,而在右侧,在可能的情况下在连接标准上匹配。根据我的经验,它通常极少使用。我有一个大型系统,只使用一次。

你似乎想要在这里做什么,因为RIGHT JOIN不可用是FULL OUTER JOIN两个集合并在两个子集之间设置了一些UNION条件,这实际上是不可能的。示例中JOIN的两个集合不能包含别名,也不能有UNION子句尝试链接它们。

答案 1 :(得分:1)

-- 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;

答案 2 :(得分:1)

上面描述的左右外连接结合在一起的方法效果很好,似乎是普遍接受的解决方案。然而,正如我在阅读留言板上阅读各种示例时所发现的那样,有一些细节遗漏了。

  1. 将用于连接的列上的表源从一个select交换到另一个,以解释外连接产生的NULL。

  2. 将COALESCE函数添加到“固定列”中,这些列也可能作为外连接产生的NULL返回。

  3. 示例:

    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`)