【问题标题】:SQL LEFT JOIN "JOIN expression is not supported"SQL LEFT JOIN“不支持 JOIN 表达式”
【发布时间】:2017-02-07 10:53:19
【问题描述】:

这个问题与我在 Sparx 网站上SQL help in finding missing operations 提出的问题有关。他们建议我尝试 StackOverflow,所以我来了。在发布到 Sparx 网站之前,我曾尝试对这个问题进行大量研究。我对它进行了微调,使其更像是一般的 SQL 问题,而不是固定在我正在使用的工具上。

我不是 SQL 专家,所以请善待我!

情况
我有 2 个包含以下元素的表

Table t_object
--------------
Object_ID AutoNumber
Object_Type Text
Name Text
ParentID Number

Table t_operation
-----------------
OperationID AutoNumber
Object_ID Number
Name Text

表 t_object 包含许多不同类型的项目。 Object_ID 是唯一键。我感兴趣的项目是 Object_Type = 'class' OR 'activity' OR 'activityparameter'。名称是项目的名称。 ParentID仅适用于'activityparameter'项,是'activityparameter'所属的'activity'的Object_ID。

表 t_operation 包含属于一个类的所有操作。 OperationID 是唯一键。 Object_ID 是这个操作如何链接到它在 t_object 中的类。

问题
在我们的系统中,所有类都有一个同名的活动,并且属于一个类的所有操作都有一个同名的活动参数属于该活动。

我正在尝试查找错误条目,其中 MyClass 类中的操作 MyOp 确实不在活动 MyClass 中具有同名的活动参数 MyOp。

使用下面的测试数据

t_object
+-----------+-------------------+-------+----------+
| Object_ID | Object_Type | Name | ParentID |
+-----------+-------------------+-------+----------+
| 1 | Class | c1 | 0 |
| 2 | Class | c2 | 0 |
| 3 | Activity | c1 | 0 |
| 4 | Activity | c2 | 0 |
| 5 | ActivityParameter | MyOp1 | 3 |
| 6 | ActivityParameter | MyOp2 | 3 |
| 7 | ActivityParameter | MyOp3 | 3 |
| 8 | ActivityParameter | MyOp1 | 4 |
| 9 | ActivityParameter | MyOp2 | 4 |
+-----------+-------------------+-------+----------+

t_operation
+-------------+-----------+-------+
| OperationID | Object_ID | Name |
+-------------+-----------+-------+
| 1 | 1 | MyOp1 |
| 2 | 1 | MyOp2 |
| 3 | 2 | MyOp1 |
| 4 | 2 | MyOp2 |
| 5 | 2 | MyOp3 |
| 6 | 2 | MyOp4 |
+-------------+-----------+-------+

以上表格代表如下

Operation c1::MyOp1 (from class c1)
Operation c1::MyOp2 (from class c1)
Operation c2::MyOp1 (from class c2)
Operation c2::MyOp2 (from class c2)
Operation c2::MyOp3 (from class c2)
Operation c2::MyOp4 (from class c2)
Activity parameter c1::MyOp1 (from activity c1)
Activity parameter c1::MyOp2 (from activity c1)
Activity parameter c1::MyOp3 (from activity c1)
Activity parameter c2::MyOp1 (from activity c2)
Activity parameter c2::MyOp2 (from activity c2)

我们可以看到以下错误

Operation c2::MyOp3 has no equivalent activity parameter
Operation c2::MyOp4 has no equivalent activity parameter
Activity parameter c1::MyOp3 has no equivalent operation

出于这个问题的目的,我对最终错误不感兴趣。当我得到“操作类::操作没有等效的活动参数”的 SQL 查询时,我将有逻辑来做相反的事情。

我尝试了 SQL 查询(我正在使用 Access 和 MySQL)。请注意,文本搜索不区分大小写。如果活动参数属于提到的活动,则 SELECT 末尾的 2 个 ID 应该相等。如果它们不同,则返回的活动参数属于不同的活动。这可以作为快速交叉检查。

SELECT o_class.name, o_operation.name, o_activity.name, o_actparam.name, o_activity.object_ID AS "activity ID", o_actparam.parentID AS "belongs to activity ID"  
FROM  
(((  
t_object o_class  
INNER JOIN t_object o_activity ON  
    (   o_activity.name = o_class.name  
       AND  
       o_class.object_type = 'class'  
       AND  
       o_activity.object_type = 'activity'  
    )  
)  
INNER JOIN t_operation o_operation ON o_operation.object_id = o_class.object_id)  
LEFT JOIN t_object o_actparam ON  
    (   o_actparam.name = o_operation.name  
        AND  
        o_actparam.object_type = 'activityparameter'  
        AND  
        o_actparam.parentid = o_activity.object_id  
    )  
)  
WHERE  
    o_actparam.name is NULL  
ORDER BY  
    o_class.name, o_operation.name, o_activity.name, o_actparam.name, o_activity.object_ID, o_actparam.parentID  

上面的目的是得到一个类,然后是一个同名的activity,然后是属于这个类的所有操作,然后对于每个操作try and find一个activity此活动中具有相同名称的参数。任何不匹配的都应返回 NULL(因为它是 LEFT JOIN),因此 WHERE 语句显示没有相关活动参数的操作,即错误。

上述方法不起作用;我收到“不支持 JOIN 表达式”。

如果我取出“o_actparam.parentid = o_activity.object_id”,那么它根本不会返回任何结果。 这显然是错误的。我相信这是因为 LEFT JOIN 匹配第一个表达式,即“o_actparam.name = o_operation.name”,然后将任何其他表达式应用于该结果。所以它返回 10 行(c2::MyOp4 一个 NULL),但第二个表达式(o_actparam.object_type = 'activityparameter')然后丢弃 NULL(c2::MyOp4)。然后所有 9 个结果都被 WHERE 子句丢弃。

如果我将 LEFT JOIN 更改为

LEFT JOIN t_object o_actparam ON  
    (   o_actparam.name = o_operation.name  
        AND  
        (   o_actparam.object_type = 'activityparameter'  
            OR  
            o_actparam.object_type is NULL  
        )  
    )  
)  

然后我得到结果

c2::MyOp4

找不到 c2::MyOp3。这是因为操作 c2::MyOp3 与活动参数 c1::MyOp3 匹配(相同的活动参数名称,即使它属于错误的类/活动 c1)。 LEFT JOIN 比较忽略类/活动。请记住,如果我检查 'o_actparam.parentid = o_activity.object_id',那么我会得到“不支持 JOIN 表达式”。

如果我将 WHERE(并保留上述 LEFT JOIN)更改为

WHERE  
    o_actparam.parentid <> o_activity.object_id  
OR  
    o_actparam.parentid is NULL  

然后我得到结果

c1::MyOp1
c1::MyOp2
c2::MyOp1
c2::MyOp2
c2::MyOp3
c2::MyOp4

现在发现很多错误的项目,因为相同的活动参数名称存在于不同的活动中。 WHERE 来不及丢弃物品,但是,将 parentid 放在 LEFT JOIN 中给了我“不支持 JOIN 表达式”的错误。

在我的研究中,我注意到我可以在 ON 子句中连接表达式,例如

LEFT JOIN t_object o_actparam ON  
    o_actparam.name + o_actparam.object_type + o_actparam.parentid = o_operation.name + 'activityparameter' + o_activity.object_id  
) 

这里的想法是,如果 LEFT JOIN 在第一个表达式上起作用,然后过滤任何后续的表达式,然后将它们全部放在一起就可以满足我的要求。它还具有不需要到处都要求“OR xxx is NULL”的好处。它还强化了我正在寻找的东西,名称、对象类型和父对象的组合。当然,上述方法不起作用(或者我不会在这里问);它仍然给出了相同的“不支持 JOIN 表达式”。同样,删除“parentID”方面会产生错误的结果。

我希望我已经给出了详细的情况、测试用例、预期的答案、我的推理和我的研究,以表明这不仅仅是“我懒得自己解决,请帮忙”。我花了几天时间在谷歌上搜索并尝试了 SQL,但正如我所说,我不是 SQL 专家。

这里有人可以帮助我吗?
谢谢
达伦

【问题讨论】:

  • 我找到了答案,所以我把它贴在这里,以防有人觉得它有用。

标签: mysql sql ms-access


【解决方案1】:

我找到了答案,所以我把它贴在这里,以防有人觉得它有用。感谢 Sandra 的帮助。

答案是我的问题 LEFT JOIN 试图访问早期表中的条目,但它看不到它们,因为我引用了 2 个不同的表。我不是 SQL 专家,所以我不知道正确的术语或确切的原因。

无论如何,解决方案是将所有以前的表放入一个子查询中,以便获得一个新的单个表名。

请注意,由于我使用的是 Access,因此有人告诉我,左连接的 ON 部分后面的括号是必不可少的,因为我连接的是一个常量值(“活动参数”)。

需要的更改是插入

(SELECT * FROM

在前 2 个表之前。请注意,这需要我将带有 3 个括号的单行分成 2 行,因为 SELECT 需要放在第一个括号之后。

然后添加一个额外的

) AS q1

在 2 张桌子之后。在下面的最终答案中,为了清楚起见,我缩进了整个部分并在前后放置了一个空行。

然后在我的 LEFT JOIN 中,我通过在每个引用的开头添加 q1. 来引用旧表。

以下查询完美运行,并给出了我预期的结果。

SELECT o_class.name, o_operation.name, o_activity.name, o_actparam.name, o_activity.object_ID AS "activity ID", o_actparam.parentID AS "belongs to activity ID"  
FROM  
(
    (SELECT * FROM
    ((  
    t_object o_class  
    INNER JOIN t_object o_activity ON  
        (   o_activity.name = o_class.name  
           AND  
           o_class.object_type = 'class'  
           AND  
           o_activity.object_type = 'activity'  
        )  
    )  
    INNER JOIN t_operation o_operation ON o_operation.object_id = o_class.object_id)  
    ) AS q1

LEFT JOIN t_object o_actparam ON  
    (   o_actparam.name = q1.o_operation.name  
        AND  
        o_actparam.object_type = 'activityparameter'  
        AND  
        o_actparam.parentid = q1.o_activity.object_id  
    )  
)  
WHERE  
    o_actparam.name is NULL  
ORDER BY  
    o_class.name, o_operation.name, o_activity.name, o_actparam.name, o_activity.object_ID, o_actparam.parentID  

【讨论】:

    猜你喜欢
    • 2020-11-30
    • 2015-04-25
    • 2016-04-18
    • 1970-01-01
    • 2015-12-14
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    相关资源
    最近更新 更多