sql - 嵌套选择中的 Oracle 11g order by 和 rownum 不适用于内部联接
问题描述
我想返回两列,其中第二列是通过外部 id 链接的用户名。我担心该州可能存在如此多条不同的记录,所以我想按一个州(自定义优先级)排序并找到第一个。
这是编辑前的工作查询。
select entry.ID,
(select username.USERNAME from USER_CREDENTIALS username
inner join CREDENTIALS cred on username.ID = cred.ID
where cred.SUBJECT_ID=entry.SUBJECTID
)
from ENTRY entry
where entry.ID in (1, 2, 5);
我的最终目标是确保内部选择最多返回一条记录(没有记录结果null
可以)。因此,对于此处描述的同一查询(来源 sqlandplsql.com)的问题,我在这里rownum
使用ORDER BY
状态 *custom 优先级)。我最终得到了这样的结果:rownum
ORDER By
select entry.ID,
(select * from
(select username.USERNAME from USER_CREDENTIALS username
inner join CREDENTIALS cred on username.ID = cred.ID
where cred.SUBJECT_ID=entry.SUBJECTID
order by case when cred.STATE = 'A' then 1 else 2 end
)
where rownum=1
)
from ENTRY entry
where entry.ID in (1, 2, 5);
这会引发异常:
[42000][904] ORA-00904: "ENTRY"."SUBJECTID": 无效标识符
我怀疑只有这样的属性才对第一级嵌套选择可见。但是,我需要通过另一个不符合可见性的选择来使用rownum
-组合。ORDER BY
"ENTRY"."SUBJECTID"
如何重写队列以消除错误并使其 rownum
安全ORDER BY
?
解决方案
您不能引用已删除多个子查询的标识符。ENTRY.SUBJECTID
在您的情况下,您在嵌套两个深度的子查询中引用并且看不到标识符。相反,您需要将过滤器移动到外部子查询:
选项1
select e.ID,
( select USERNAME
from (
select c.SUBJECT_ID,
u.USERNAME
from USER_CREDENTIALS u
inner join CREDENTIALS c
on ( u.ID = c.ID )
order by case when STATE = 'A' then 1 else 2 end
) t
WHERE t.SUBJECT_ID = e.SUBJECTID
AND rownum=1
) AS username
from ENTRY e
where e.ID in (1, 2, 5);
选项 2
或者通过使用ROW_NUMBER
解析函数:
select e.ID,
( select USERNAME
from (
select c.SUBJECT_ID,
u.USERNAME,
ROW_NUMBER() OVER (
PARTITION BY c.SUBJECT_ID
ORDER BY case when STATE = 'A' then 1 else 2 end
) As rn
from USER_CREDENTIALS u
inner join CREDENTIALS c
on ( u.ID = c.ID )
) t
WHERE t.SUBJECT_ID = e.SUBJECTID
AND rn=1
) AS username
from ENTRY e
where e.ID in (1, 2, 5);
其中,对于样本数据:
CREATE TABLE entry ( id, subjectid ) AS
SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 5;
CREATE TABLE credentials ( id, subject_id ) AS
SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 5;
CREATE TABLE user_credentials ( id, username, state ) AS
SELECT LEVEL, 'NameA' || LEVEL, 'A' FROM DUAL CONNECT BY LEVEL <= 4 UNION ALL
SELECT LEVEL, 'NameB' || LEVEL, 'B' FROM DUAL CONNECT BY LEVEL <= 5;
两个输出:
身份证 | 用户名 -: | :-------- 1 | 名称A1 2 | 名称A2 5 | 名称B5
db<>在这里摆弄
如果您使用的是 Oracle 12,则可以使用以下FETCH FIRST ROW ONLY
语法:
select e.ID,
( select u.USERNAME
from USER_CREDENTIALS u
inner join CREDENTIALS c
on ( u.ID = c.ID )
WHERE t.SUBJECT_ID=e.SUBJECTID
order by case when STATE = 'A' then 1 else 2 end
FETCH FIRST ROW ONLY
)
from ENTRY e
where e.ID in (1, 2, 5);
(EXPLAIN PLAN
与ROW_NUMBER
解析解相同)。
db<>在这里摆弄
推荐阅读
- ios - iOS 集合视图装饰视图:补充视图的子类
- laravel - 在 Laravel 中对 Google Document AI 的 v1 API 进行身份验证
- php - WooCommerce:获取单个产品的价格和描述
- reactjs - 如何在 Azure 上的不同 URL 中为每个 PR 部署 React App?
- javascript - 如何使用 typeof 运算符检查函数是否为字符串
- pytorch - 是否可以在 brython 脚本中运行 PyTorch?
- ansible - 基于先前命令输出的 Ansible win_shell 循环
- angular - 用于 Msal 和 B2C 的 Angular Azure 登录切换键
- javascript - 如何在不使用 Moment.js 持续时间功能的情况下处理持续时间?
- google-apps-script - 在 Google Apps 脚本中有没有办法在独立项目中重新排序工作表/选项卡?