MySQL FROM多个表LEFT JOIN'on clause'中的未知列

时间:2012-06-08 02:43:50

标签: php mysql silverstripe

我有一个有趣的查询,我似乎遇到了麻烦。

我需要从多个表中选择数据并加入另一个表,该表的列可能不存在于其他表中。

我已经尝试了几个角度。这是第一个:

SELECT SiteTree.*, Page.*, AlbumItem.*, Album.*
FROM SiteTree, AlbumItem, Album
LEFT JOIN Page ON SiteTree.ID = Page.ID

抛出这个:#1054 - 'on子句'中的未知列'SiteTree.ID',可能是因为当从Album表中选择时尝试加入时没有SiteTree.ID列。

我也试过这个:

SELECT SiteTree.*, Page.*, AlbumItem.*, Album.*
FROM SiteTree LEFT JOIN Page ON SiteTree.ID = Page.ID, AlbumItem, Album

返回约20行,我知道应该只有2基于where子句。事实上,每个结果行大约有10个副本

where where子句如下:

WHERE (
    (
        AlbumItem.ClassName = 'AlbumItem' OR 
        Album.ClassName = 'Album' OR 
        SiteTree.ClassName = 'Page' OR 
        SiteTree.ClassName = 'HomePage' OR 
        SiteTree.ClassName = 'NewsCategory' OR
        SiteTree.ClassName = 'NewsArticle' OR
        SiteTree.ClassName = 'CartPage' OR
        SiteTree.ClassName = 'Product' OR
        SiteTree.ClassName = 'ProductGroup' OR
        SiteTree.ClassName = 'MemberProfilePage' OR
        SiteTree.ClassName = 'SubscriptionPage' OR
        SiteTree.ClassName = 'ErrorPage' OR
        SiteTree.ClassName = 'RedirectorPage' OR
        SiteTree.ClassName = 'VirtualPage' OR
        SiteTree.ClassName = 'UserDefinedForm' OR
        SiteTree.ClassName = 'CheckoutPage' OR
        SiteTree.ClassName = 'OrderConfirmationPage' OR
        SiteTree.ClassName = 'TagPage'
    ) AND (
       INSTR(Page.Tags,'x') OR
       INSTR(AlbumItem.Tags,'x') OR
       INSTR(Album.Tags,'x')
    )
)

将查询减少到这会产生正确的结果,但它也不适用于其他表:

SELECT SiteTree.*, Page.*
FROM SiteTree
LEFT JOIN Page ON SiteTree.ID = Page.ID

我需要知道的是,如果我不想诉诸工会,我想做什么呢?

3 个答案:

答案 0 :(得分:1)

AlbumItemAlbum缺少实际的加入条件会导致(偶数)完全外部加入/交叉加入问题。您应该正确加入这两个表。否则,您将为每个表格获得至少一条记录。

答案 1 :(得分:1)

好的,我现在有一个有效的查询。

为了正确看待我,我正在SilverStripe中构建一个可标记的模块。 SilverStripe中的ORM允许将扩展添加到多个DataObject,这些DataObject可能具有唯一的表集,这些表不共享公共列以执行带有JOIN子句的ON

在尝试生成查询时,我试图使用SQLQuery对象的限制。 SilverStripe中的SQLQuery对象不支持UNION所以我希望我不必生成完整的原始SQL查询。似乎没有办法避免使用UNION来避免产生笛卡尔积。

所以我最终为PDO制作了一个瘦包装器,并使用基于UNION的查询,如下所示。它是在脚本中自动生成的,该脚本遍历对象图以查找所有相关表,因此它比我手动编写时更加冗长。此外,它应该使用正则表达式匹配,因此匹配更准确,但在这个时间点我更关心查询产生一些可用的输出:

SELECT SQL_CALC_FOUND_ROWS SiteTree.ClassName, SiteTree.ID
FROM SiteTree LEFT JOIN Page ON SiteTree.ID = Page.ID
WHERE (
    SiteTree.ClassName = 'Page' OR 
    SiteTree.ClassName = 'HomePage' OR 
    SiteTree.ClassName = 'NewsCategory' OR 
    SiteTree.ClassName = 'NewsArticle' OR 
    SiteTree.ClassName = 'GalleryPage' OR 
    SiteTree.ClassName = 'CartPage' OR 
    SiteTree.ClassName = 'Product' OR 
    SiteTree.ClassName = 'ProductGroup' OR 
    SiteTree.ClassName = 'MemberProfilePage' OR 
    SiteTree.ClassName = 'SubscriptionPage' OR 
    SiteTree.ClassName = 'ErrorPage' OR 
    SiteTree.ClassName = 'RedirectorPage' OR 
    SiteTree.ClassName = 'VirtualPage' OR 
    SiteTree.ClassName = 'UserDefinedForm' OR 
    SiteTree.ClassName = 'CheckoutPage' OR 
    SiteTree.ClassName = 'OrderConfirmationPage' OR
    SiteTree.ClassName = 'TagPage'
) AND (
    INSTR(Page.Tags,'x')
)

UNION ALL

SELECT AlbumItem.ClassName, AlbumItem.ID
FROM AlbumItem
WHERE (AlbumItem.ClassName = 'AlbumItem') AND (INSTR(AlbumItem.Tags,'x'))

UNION ALL

SELECT Album.ClassName, Album.ID
FROM Album
WHERE (Album.ClassName = 'Album') AND (INSTR(Album.Tags,'x'))

LIMIT 0,40

答案 2 :(得分:0)

ID表中是否有一个名为SiteTree的列?鉴于错误消息,没有。修复此问题,以便您引用表中实际存在的列。

另外,你为什么要做ANSI JOIN(即使用,...)......你应该INNER JOIN,因为否则你将得不到你所期望的。