如何简化这个子查询?

Posted

技术标签:

【中文标题】如何简化这个子查询?【英文标题】:How to simplify this subquery? 【发布时间】:2015-02-04 08:56:16 【问题描述】:

我从http://www.programmerinterview.com/index.php/database-sql/derived-table-vs-subquery/ 看到了这个子查询,它以下面的子查询为例,但说它可以写得更简单。谁能告诉我该怎么做?谢谢!

一个名为employee 的表,其中包含employee_name、last_name、employee_salary 和employee_number 列。我们希望找到所有薪水高于平均水平的员工。

   select employee_name 
    from employee
    where employee_salary >
    (select avg(employee_salary)
            from employee)

【问题讨论】:

对我来说似乎很简单。 我猜;他们指的是SELF JOIN;详细说明@programmerinterview.com/index.php/database-sql/… 【参考方案1】:

试试这个:

SELECT employee_name 
FROM employee e 
INNER JOIN (SELECT AVG(employee_salary) salary FROM employee) e1 ON e.employee_salary > e1.salary;

SELECT employee_name 
FROM employee e 
WHERE EXISTS (SELECT 1 FROM employee e1 WHERE e.employee_salary > AVG(e1.employee_salary)); 

【讨论】:

【参考方案2】:

我认为您的查询设计得很好。 使用 JOIN 效率会降低,并且 HAVING 子句将在检索后过滤数据。您将获取所有员工,然后过滤平均工资。

【讨论】:

【参考方案3】:

希望这会有所帮助

--DECLARE A TABLE VARIABLE
DECLARE @Emp AS TABLE

(
     ID                 INT
    ,EMPLOYEE_NAME      VARCHAR(50)
    ,EMPLOYEE_SALARY    NUMERIC(18,2)

)
-- ADD SOME VALUES TO THE TABLE
INSERT INTO @Emp
VALUES (1,'DANNY',7000),(2,'JOHN',10000),(3,'DAVID',1000)

--AVERAGE SALARY IS 6000..

--USING COMMON TABLE EXPRESSIONS
    ; WITH CTE AS
     (
        SELECT 
            AVG(EMPLOYEE_SALARY)  AS AVGSALARY
        FROM @EMP       
    )
        SELECT 
            EMPLOYEE_NAME
        FROM 
            @Emp    EMPLOYEE    -- MY TABLE
        INNER JOIN
            CTE
        ON
            EMPLOYEE_SALARY>CTE.AVGSALARY

【讨论】:

【参考方案4】:

您可以使用OVER 子句计算average 的薪水以及当前员工的薪水是否大于它。很遗憾,window 函数不能在 where 子句中使用,所以你也应该使用命令表表达式。

DECLARE @employee TABLE
(
     [employee_name] VARCHAR(12)
    ,[employee_salary] INT
)

INSERT INTO @employee ([employee_name], [employee_salary])
VALUES ('Empl1', 100)
      ,('Empl2', 200)
      ,('Empl3', 300)
      ,('Empl4', 400)
      ,('Empl5', 500)
      ,('Empl6', 600)
      ,('Empl7', 700)
      ,('Empl8', 800)

-- your query
 select employee_name 
    from @employee
    where employee_salary >
    (select avg(employee_salary)
            from @employee)

-- alternative query
;WITH DataSource AS
(
     select employee_name
           ,employee_salary - AVG(employee_salary) OVER () AS diff
     from @employee
 )
 SELECT employee_name
 FROM DataSource
 WHERE diff > 0

【讨论】:

有趣的方法,但是针对 300,000 行的表测试这两个查询,原始查询的执行比使用 OVER 的查询要好约 5.5 倍(相对于批处理的成本为 15% 与 85%)。 【参考方案5】:

sql server 2012

    select iif(((employee_salary) > (SELECT avg(employee_salary) FROM employee)),
            employee_name ,null) employee_name 
    FROM employee
    group by employee_name,employee_salary 

【讨论】:

这个查询甚至无法编译。

以上是关于如何简化这个子查询?的主要内容,如果未能解决你的问题,请参考以下文章

Mysql创建SQL子查询ALIAS

MySQL - 如何将子查询中的列别名用于另一个子查询?

UDF 与子查询性能问题

如何按名称查找不匹配的第n个子行?

如何从子查询中返回两个字段

如何使用从一个子查询到另一个子查询的列