首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有“`CROSS”和“`OUTER”的不一致行为

具有“`CROSS”和“`OUTER”的不一致行为
EN

Stack Overflow用户
提问于 2017-03-04 06:58:55
回答 2查看 817关注 0票数 7

我在Oracle-12c中有一个类似于accountspostscomments的典型论坛的模式。我只写了一个查询.

  1. 一个用户
  2. 所有用户的帖子
  3. 对每一个职位的评论
  4. 以及每条评论的作者。

该查询如下所示:

代码语言:javascript
复制
select "accounts".*, "p".*, "c".*, "author".*
from "accounts"
cross apply (
    select * from "posts"
    where "posts"."author_id" = "accounts"."id"
) "p"
cross apply (
    select * from "comments"
    where "comments"."post_id" = "p"."id"
) "c"
left join "accounts" "author" on "author"."id" = "c"."author_id"
where "accounts"."id" = 1

这个查询就像预期的那样工作。我使用的是CROSS APPLY而不是一个典型的连接,因为稍后我将添加OFFSETFETCH来分页。然而,问题是CROSS APPLY忽略了没有评论的帖子,我不想这样做。我想保持在结果中的文章,即使他们没有评论。

因此,我尝试将CROSS APPLY改为OUTER APPLY

代码语言:javascript
复制
select "accounts".*, "p".*, "c".*, "author".*
from "accounts"
outer apply (
    select * from "posts"
    where "posts"."author_id" = "accounts"."id"
) "p"
outer apply (
    select * from "comments"
    where "comments"."post_id" = "p"."id"
) "c"
left join "accounts" "author" on "author"."id" = "c"."author_id"
where "accounts"."id" = 1

但现在我发现了一个错误:

代码语言:javascript
复制
ORA-00904: "p"."id": invalid identifier
00904. 00000 -  "%s: invalid identifier"
*Cause:    
*Action:
Error at Line: 9 Column: 34

出于某种原因,我的第二个OUTER APPLY连接抱怨我引用了第一个"p"."id"的结果。但是,当我使用CROSS APPLY的时候,这很好。

怎么一回事?为什么这两者之间的行为有这么大的区别?

编辑:在这个基本的例子中,OUTER APPLY似乎是不必要的。这是从一个更复杂的场景中提炼出来的,在这个场景中,我必须坚持认为,OUTER APPLY确实是必要的,但这个场景的细节与我提出的实际问题无关--这个问题是关于CROSSOUTER APPLY之间似乎没有记录的行为差异的。

编辑:

Oracle版本:数据库12c标准版12.1.0.2.0 -64位生产

客户端: Oracle版本4.2.0.16.356

服务器:uname -a - Linux ubuntu-1gb-sfo2-01 4.4.0-64-generic #85-Ubuntu SMP Mon Feb 20 11:50:30 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux输出

DDL: 链接

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-06 22:42:14

对于CodeFuller's的回答,我只想补充一点:(A)这个bug有一个可用的修补程序,(B)有一个在12.1.0.2中工作的工作SQL,尽管我不知道它是否能满足您的目的。

解决办法是基本上嵌套连接,如下所示:

代码语言:javascript
复制
SELECT accounts.*,
       p.*,
       author.*
FROM   accounts
       CROSS APPLY (SELECT posts.id,
                           posts.author_id,
                           posts.text,
                           comments.comment_author_id,
                           comments.comment_text
                    FROM   posts
                           OUTER APPLY (SELECT comments.author_id comment_author_id,
                                               comments.text comment_text
                                        FROM   comments
                                        WHERE  comments.post_id = posts.id) comments
                    WHERE  posts.author_id = accounts.id) p
       LEFT JOIN accounts author
         ON author.id = p.comment_author_id
WHERE  accounts.id = 1;


ID   NAME      ID_1 AUTHOR_ID TEXT                                              COMMENT_AUTHOR_ID COMMENT_TEXT                            ID_2  NAME_1                               
---- --------- ---- --------- ------------------------------------------------- ----------------- --------------------------------------- ----- ------------------- 
   1 Fred         1         1 Fred wrote this and it has comments                               3 This is Helen's comment on Fred's post      3 Helen                                
   1 Fred         2         1 Fred wrote this and it does not have any comments
-------- End of Data --------
2 row(s) fetched

参考:表DDL用于解决方法

代码语言:javascript
复制
CREATE TABLE accounts
(
  id     NUMBER PRIMARY KEY,
  name   VARCHAR2 (30)
);

CREATE TABLE posts
(
  id          NUMBER PRIMARY KEY,
  author_id   NUMBER,
  text        VARCHAR2 (240)
);

CREATE TABLE comments
(
  id          NUMBER PRIMARY KEY,
  post_id     NUMBER,
  author_id   NUMBER,
  text        VARCHAR2 (240)
);

INSERT INTO accounts (id, name)
VALUES (1, 'Fred');

INSERT INTO accounts (id, name)
VALUES (2, 'Mary');

INSERT INTO accounts (id, name)
VALUES (3, 'Helen');

INSERT INTO accounts (id, name)
VALUES (4, 'Iqbal');

INSERT INTO posts (id, author_id, text)
VALUES (1, 1, 'Fred wrote this and it has comments');

INSERT INTO posts (id, author_id, text)
VALUES (2, 1, 'Fred wrote this and it does not have any comments');

INSERT INTO posts (id, author_id, text)
VALUES (3, 4, 'Iqbal wrote this and it does not have any comments');

INSERT INTO comments (id,
                      post_id,
                      author_id,
                      text)
VALUES (1,
        1,
        3,
        'This is Helen''s comment on Fred''s post');
票数 11
EN

Stack Overflow用户

发布于 2017-03-06 19:28:58

您的查询没有任何问题。您已经遇到了20356733/21547130错误,这是在12.1.0.2中引入的,正如这里所描述的那样。为了克服这一问题,请在12.1.0.2之前使用版本,或者应用最新的更新(在12.1.0.2.160419修补程序集更新中可以使用链接线程声明修复)。

这个答案主要是由马修McPeak马丁·史密斯找到的。我刚刚进行了第一次尝试,如下所述,并发现这个问题在Oracle 12.1.0.1上是不可复制的。

第一答案尝试:

我用您的模式创建了测试数据库,这两个查询对我来说都很好。第一个不返回没有注释的帖子,第二个返回所有帐户帖子,没有任何ORA-00904错误。我在Oracle 12c上做了这个测试。

继续提出你的问题:

  1. 尝试从你的帖子中复制/粘贴并执行第二次查询。有时,一些令人讨厌的小排字潜入查询中。准确的查询,从您的帖子,为我工作,如预期。
  2. 如果仍然收到相同的错误,请提供用于创建accountspostscomments表的DDL。
  3. 请指定您使用的SQL客户端。错误肯定发生在服务器端,但在这种奇怪的情况下,每一个微小的细节都会产生影响。

我的测试数据库:

代码语言:javascript
复制
CREATE TABLE "accounts"
(
    "id" NUMBER(11) NOT NULL,
    "name" NVARCHAR2(256),
    CONSTRAINT ACCOUNTS_PK PRIMARY KEY ("id")
)
/

CREATE TABLE "posts"
(
    "id" NUMBER(11) NOT NULL,
    "author_id" NUMBER(11) NOT NULL,
    "post_text" NVARCHAR2(1024),
    CONSTRAINT POSTS_PK PRIMARY KEY ("id"),
    CONSTRAINT POST_ACCOUNT_FK FOREIGN KEY ("author_id") REFERENCES "accounts" ("id") ON DELETE CASCADE
)
/

CREATE TABLE "comments"
(
    "id" NUMBER(11) NOT NULL,
    "author_id" NUMBER(11) NOT NULL,
    "post_id" NUMBER(11) NOT NULL,
    "comment_text" NVARCHAR2(1024),
    CONSTRAINT COMMENTS_PK PRIMARY KEY ("id"),
    CONSTRAINT COMMENT_ACCOUNT_FK FOREIGN KEY ("author_id") REFERENCES "accounts" ("id") ON DELETE CASCADE,
    CONSTRAINT COMMENT_POST_FK FOREIGN KEY  ("post_id") REFERENCES "posts" ("id") ON DELETE CASCADE
)
/

INSERT INTO "accounts"("id", "name") VALUES(1, 'testuser')
/
INSERT INTO "posts"("id", "author_id", "post_text") VALUES(1, 1, 'First test post')
/
INSERT INTO "posts"("id", "author_id", "post_text") VALUES(2, 1, 'Second test post')
/
INSERT INTO "comments"("id", "author_id", "post_id", "comment_text") VALUES(1, 1, 2, 'It is a very cool post')
/
COMMIT
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42593148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档