Oracle中的分组和窗口函数

哈Ha!在我工作的公司里,经常聚会(请见谅。)其中之一是我的一位同事关于Oracle Windowing and Grouping的演讲。在我看来,这个话题值得发表。







从一开始,我想澄清一下,在这种情况下,Oracle是作为一种集体SQL语言呈现的。分组及其应用方式适用于整个SQL系列(在这里被理解为结构化查询语言),并且适用于所有查询,并且对每种语言的语法进行了更正。



我将尝试在两个部分中简要而轻松地解释所有必要的信息。这篇文章对新手开发人员很有用。谁在乎-欢迎来到猫。



第1部分:产品订购依据,分组依据,拥有



在这里,我们将讨论排序-排序依据,分组-分组依据,过滤-具有和查询计划。但是首先是第一件事。



排序依据



Order by运算符对输出值进行排序,即按特定列对检索到的值进行排序。排序也可以通过使用运算符定义的列别名来应用。



Order by的优点是它可以应用于数字列和字符串列。字符串列通常按字母顺序排序。



默认情况下应用升序排序。如果要按降序对列进行排序,请使用其他DESC运算符。



语法:



SELECT column1,column2, …(表示名称)

FROM table_name

ORDER BY column1,column2ASC | DESC ;



让我们用示例来看看一切:





在第一个表中,我们获取所有数据,并按ID列升序对其进行排序。



在第二个中,我们还获取了所有数据。使用DESC关键字按ID列按降序排序



第三个表使用几个排序字段。首先是按部门排序。如果第一个运算符等于相同部门的字段,则应用第二个排序条件;在我们的例子中,这是工资。



很简单 我们可以设置多个排序条件,这使我们可以更智能地对输出列表进行排序。



通过...分组



在SQL中,Group by子句收集从特定组中的数据库检索的数据。分组将所有数据划分为逻辑集,以便可以在每个组中分别执行统计计算。



该运算符用于按一列或多列组合选择的结果。分组后,该列中使用的每个值将只有一个条目。



SQL Group by语句的使用与聚合函数和SQL Have语句的使用紧密相关。 SQL中的聚合函数是一种在一组列值上返回单个值的函数。例如:COUNT(),MIN(),MAX(),AVG(),SUM()



语法:



SELECT column_name(s)

FROM table_name

WHERE 条件

GROUP BY 列名(多个)

ORDER BY 列名(多个);



分组依据出现在SELECT查询中的条件WHERE子句之后(可选)您可以使用ORDER BY对输出值进行排序。 因此,根据上一个示例中的表,我们需要找到每个部门员工的最高工资。最终样本应包括部门名称和最高工资。 解决方案1(不使用分组):











SELECT DISTINCT
    ie.department
    ie.slary
    FROM itx_employee ie
    WHERE ie.salary = (
             SELECT
             max(ie1.salary)
             FROM itx_employee ie1
             WHERE ie.department = ie1.department
             )


解决方案2(使用分组):



SELECT
department,
max(salary)
FROM itx_employee
GROUP BY department


在第一个示例中,我们不使用分组即可解决问题,而是使用子选择,即 一选二。在第二个解决方案中,我们使用分组。



尽管第二个示例执行与第一个示例相同的功能,但它更短并且更具可读性。



Group by如何为我们工作:首先将两个部门分为质量保证小组和开发小组。然后,他为每个人寻找最高薪水。





拥有是一个过滤工具。它指示执行聚合功能的结果。在无法使用WHERE的SQL中使用了Haveing。



如果WHERE子句定义了一个用于过滤行的谓词,那么在分组之后使用Haveing来定义一个逻辑谓词,该逻辑谓词通过聚合函数的值来过滤该组。该子句对于测试使用从行组的聚合函数获得的值是必需的。



语法:



SELECT 列名(S)

FROM TABLE_NAME

WHERE 条件

GROUP BY 列名(多个)

HAVING 条件



首先,我们用平均薪水高显示比部门4000然后,我们使用显示滤波的最高薪水。



解决方案1(不使用GROUP BY和HAVING):



SELECT DISTINCT
ie.department AS "DEPARTMENT",
(
     (SELECT
     AVG(ie1.salary)
     FROM itx_employee ie1
     WHERE ie1.department = ie.department)
) AS "AVG SALARY"

FROM itx_employee ie
where (SELECT
     AVG(ie1.salary)
     FROM itx_employee ie1
     WHERE ie1.department = ie.department) > 4000




解决方案2(使用GROUP BY和HAVING):



SELECT
department, 
AVG(salary)

FROM itx_employee 
GROUP BY department
HAVING AVG(salary) > 4000




第一个示例使用两个子选择,一个选择最高薪水,另一个选择平均薪水。同样,第二个示例更简单,更简洁。



索取方案



在很多情况下,请求会花费很长时间,从而消耗大量的内存和磁盘资源。要了解为什么查询长时间运行且效率低下,我们可以查看查询计划。



查询计划是查询的预期执行计划,即DBMS将如何执行它。 DBMS将记下将在子查询中执行的所有操作。分析完所有内容后,我们将能够了解查询中的弱点所在,并使用查询计划可以对其进行优化。



Oracle中任何SQL语句的执行都会检索所谓的“执行计划”。该查询执行计划描述了Oracle将如何根据正在执行的SQL语句来获取数据。计划是一棵树,其中包含步骤的顺序及其之间的关系。



可以用来获取查询的估计执行计划的工具包括Toad,SQL Navigator,PL / SQL Developer等。它们提供了查询资源消耗的许多指标,其中主要包括:成本-执行成本和基数(或)-基数(或数量)行)。



这些指标的值越高,查询的效率越低。



在下面,您可以查看查询计划的分析。第一种解决方案使用子选择,第二种使用分组。请注意,第一个解决方案处理了22行,第二个解决方案处理了15行。



查询计划分析:







另一个使用两个子选择的查询计划分析:





该示例是SQL工具使用效率低下的一种变体,我不建议您在查询中使用它。



上述所有功能将使编写查询时的工作变得更轻松,并提高代码的质量和可读性。



第2部分:窗口函数



窗口函数可追溯到Microsoft SQL Server2005。它们对Select子句中给定范围的行执行计算。简而言之,“窗口”是一组在其中进行计算的行。 “窗口”使您可以减少数据并更好地处理它。此功能使您可以将整个数据集拆分为多个窗口。



窗口化具有巨大的优势。无需创建用于计算的数据集,该数据集使您可以使用唯一的ID保存该集的所有行。窗口功能的结果在另一个字段中添加到结果选择中。



语法:



SELECT column_name(s)

聚合函数(要计算的列)

OVER([ PARTITION BY [要分组的列]

FROM table_name

[要排序的ORDER BY列]

[[ ROWSRANGE表达式以限制组中的行]])



OVER PARTITION BY是用于设置窗口大小的属性。您可以在此处指定其他信息,提供服务命令,例如添加行号。窗口函数语法正好适合列选择。



让我们看一个例子:另一个部门已添加到我们的表中,现在表中有15行。我们将尝试撤离雇员,他们的薪水以及组织的最高薪水。





在第一个字段中,我们取名字,在第二个字段中,我们取工资。接下来,我们在()上使用window函数...我们使用它来获得整个组织的最高薪水,因为没有显示“窗口”的大小。带有空括号的Over()适用于整个选择。因此,每个地方的最高工资是10,000,窗口函数的结果将添加到每一行。



如果我们从查询的第四行中删除对window函数的提及,即仅max(salary)保留,该请求将不起作用。最高工资根本无法计算。由于数据将逐行处理,并且在调用max(薪水)时,当前行中只有一个数字,即现有员工。在这里您可以看到窗口功能的优势。在通话时,它适用于整个窗口以及所有可用数据。



让我们看另一个需要显示每个部门的最高薪资的示例:







实际上,我们为“窗口”设置了框架,将其划分为多个部门。我们使用部门作为排名示例。我们有三个部门:开发,质量保证和销售部门。



“窗口”查找每个部门的最高工资。通过选择,我们发现它首先找到了开发人员的最高薪水,然后是质量保证,然后是销售。如上所述,窗口函数的结果将写入每行的提取结果中。



在前面的示例中,未指定over之后的括号。在这里,我们使用了PARTITION BY,它允许我们设置窗口的大小。在这里,您可以指定一些其他信息,发送服务命令,例如行号。



结论



SQL并不像乍看起来那样简单。上述所有内容都是窗口功能的基本功能。在他们的帮助下,您可以“简化”我们的要求。但是其中蕴藏着更多的潜力:可以将实用程序运算符(例如,ROWS或RANGE)组合在一起,为查询添加更多功能。



我希望该帖子对对此主题感兴趣的每个人都有用。



All Articles