select子查询

本文探讨了SQL中使用子查询代替表连接时遇到的问题,特别是当子查询返回多行时如何通过限制返回行数来解决ORA-01427错误。通过对部门表进行修改并插入重复记录,演示了如何正确处理一对多的关系。

典型的写法
 select empno, ename, sal, dname, loc
   from emp, dept
  where emp.deptno = dept.deptno

子查询的写法(dname和loc这里是分开写的,他们不能写到一个子查询里面)
 select empno,
        ename,
        sal,
        (select dname from dept where emp.deptno = dept.deptno) dname,
        (select loc from dept where emp.deptno = dept.deptno) loc
   from emp

这里的emp和dept表都是最系统自带的,没有改动过

这里注意dept表的结构,deptno和dname、loc都是一一对应的
SQL> select * from dept;
 
DEPTNO DNAME          LOC
------ -------------- -------------
    10 ACCOUNTING     NEW YORK
    20 RESEARCH       DALLAS
    30 SALES          CHICAGO
    40 OPERATIONS     BOSTON
 

-----------------------------------------------------------------------------------
进行如下改动
SQL> create table deptx as select * from dept;
SQL> insert into deptx values(10,'xxx','yyy');
SQL> select * from deptx;
 
DEPTNO DNAME          LOC
------ -------------- -------------
    10 ACCOUNTING     NEW YORK
    20 RESEARCH       DALLAS
    30 SALES          CHICAGO
    40 OPERATIONS     BOSTON
    10 xxx            yyy


再次执行如下SQL会报错 ORA-01427:d单行子查询返回多个行,原因在于这里的deptno=10时,dname出现的是2个值了,
而在和emp做连接的时候,ename的deptno等于10时不知道是选哪个dname,也就是说还是做连接的deptno出了问题,
deptno 在一边对应一个值,在另一边对应2个值
  select deptno,
        ename,
        sal,
        (select dname from deptx where emp.deptno = deptx.deptno) dname,
        (select loc from deptx where emp.deptno = deptx.deptno) loc
   from emp

改写如下
   select deptno,
        ename,
        sal,
        (select dname from deptx where emp.deptno = deptx.deptno and rownum<=1) dname,
        (select loc from deptx where emp.deptno = deptx.deptno and rownum<=1) loc
   from emp
 
DEPTNO ENAME            SAL DNAME          LOC
------ ---------- --------- -------------- -------------
    20 SMITH          99.00 RESEARCH       DALLAS
    30 ALLEN          99.00 SALES          CHICAGO
    30 WARD           99.00 SALES          CHICAGO
    20 JONES          99.00 RESEARCH       DALLAS
    30 MARTIN         99.00 SALES          CHICAGO
    30 BLAKE          99.00 SALES          CHICAGO
    10 CLARK          99.00 ACCOUNTING     NEW YORK
    20 SCOTT          99.00 RESEARCH       DALLAS
    10 KING           99.00 ACCOUNTING     NEW YORK
    30 TURNER         99.00 SALES          CHICAGO
    20 ADAMS          99.00 RESEARCH       DALLAS
    30 JAMES          99.00 SALES          CHICAGO
    20 FORD           99.00 RESEARCH       DALLAS
    10 MILLER         99.00 ACCOUNTING     NEW YORK
 
14 rows selected
这里看可以从结果看出10返回的是对应的NEW YORK而不是yyy

出现问题的在于deptno做连接这个地方,emp的deptno是外键,它的参照列是dept的deptno,dept.deptno作为人家外键的参照列应该是主键约束,通俗的说
dept是emp的维度表,那么这里出现了一个纬度号对应了多个纬度列

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10678398/viewspace-695728/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10678398/viewspace-695728/

<think>嗯,用户这次问的是“Select 查询”,看起来是想了解在MySQL中如何在SELECT语句中使用查询。之前他们问过关于MySQL查询的基本概念,现在可能是在深入学习具体用法。 首先,我需要确认SELECT查询的不同应用场景。比如,查询可以出现在SELECT列表中作为字段,或者在FROM、WHERE、HAVING等句中。用户可能想知道如何正确使用这些位置的查询,以及需要注意的地方。 用户可能已经知道基本的查询概念,但需要具体的例和语法说明。比如,SELECT列表中的查询必须返回单个值,否则会报错。这时候需要举一个例,比如计算每个部门的平均工资,然后在主查询中显示每个员工的工资与部门平均的差额。 还要考虑性能问题,比如在SELECT列表中使用相关查询可能导致性能下降,这时候建议使用JOIN或者窗口函数替代。同时,要提醒用户注意查询的执行次数,尤其是在存在循环依赖的情况下。 另外,用户可能会遇到错误,比如查询返回多行导致的错误。这时候需要用聚合函数或者IN、ANY、ALL等操作符来处理。比如,如果查询返回多行,用=号比较就会报错,应该用IN或者比较操作符配合ANY/ALL。 还要提到别名的问题,当查询在FROM句中时必须要有别名,否则会报错。这可能是一个常见的错误点,需要举例说明。 最后,总结一些最佳实践,比如保持查询简洁、使用索引优化、避免过度嵌套等。同时,给出几个相关问题,帮助用户进一步理解和应用SELECT查询。 </think>SELECT查询是指在SELECT语句中嵌套查询,其核心作用是**将查询结果作为字段值或条件表达式**。根据使用位置不同可分为以下三类: ### 1. SELECT列表中的查询(标量查询) ```sql -- 查询每个员工工资与部门平均工资的差额 SELECT name, salary, (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id) AS avg_salary FROM employees e; ``` > ⚠️ 注意:查询必须返回**单个值**,否则报错1242 ### 2. FROM句中的查询(派生表) ```sql -- 查询各部门工资高于本部门平均的员工 SELECT e.name, e.salary, d.dept_avg FROM employees e JOIN ( SELECT department_id, AVG(salary) AS dept_avg FROM employees GROUP BY department_id ) AS d ON e.department_id = d.department_id WHERE e.salary > d.dept_avg; ``` > ⚠️ 必须为查询结果集指定**别名** ### 3. WHERE/HAVING中的查询 ```sql -- 查询比研发部平均工资高的员工 SELECT * FROM employees WHERE salary > ( SELECT AVG(salary) FROM employees WHERE department_id = (SELECT id FROM departments WHERE name = '研发部') ); ``` ### 性能优化技巧 1. **避免相关查询**:如`SELECT ... FROM t1 WHERE col = (SELECT ... FROM t2 WHERE t2.id = t1.id)`,可改写为JOIN 2. **优先使用窗口函数**:MySQL 8.0+推荐使用`AVG() OVER()`替代标量查询 3. **添加索引约束**:对查询涉及的字段创建组合索引 4. **限制结果集大小**:通过WHERE条件过滤减少查询数据量 ### 典型错误场景 ```sql -- 错误示例:SELECT列表中返回多行 SELECT id, (SELECT name FROM departments) AS dept_name -- 报错1242 FROM employees; -- 正确写法: SELECT id, (SELECT name FROM departments WHERE id = e.department_id) AS dept_name FROM employees e; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值