腾讯微信网站建设价格,郑州网站推广营销,wordpress新写文章会卡死,网站ip做网站PostgreSQL 中 DISTINCT 的多种面孔 发布日期#xff1a;2017年5月11日 原文链接#xff1a;https://hakibenita.com/the-many-faces-of-distinct-in-postgre-sql PostgreSQL 中 DISTINCT 的三种有趣用法 我的编程生涯始于一名 Oracle DBA。几年后#xff0c;我最终厌倦了企…PostgreSQL 中 DISTINCT 的多种面孔发布日期2017年5月11日原文链接https://hakibenita.com/the-many-faces-of-distinct-in-postgre-sqlPostgreSQL 中 DISTINCT 的三种有趣用法我的编程生涯始于一名 Oracle DBA。几年后我最终厌倦了企业界开始自己单干。当我不再拥有 Oracle 企业版的舒适保障后我发现了 PostgreSQL。在我克服了没有合适的分区功能和MERGE语句即 UPSERT的初期不适后我找到了一些 PostgreSQL 独有的优秀特性。奇怪的是其中很多都包含DISTINCT这个词。DISTINCT我使用这个网站上的模拟数据创建了一个简单的员工表包含姓名、部门和薪水字段haki# \d employeeColumn|Type|Modifiers----------------------------------------------id|integer|notnullname|charactervarying(30)|department|charactervarying(30)|salary|integer|haki# select * from employee limit 5;id|name|department|salary--------------------------------------------------1|Carl Frazier|Engineering|30522|Richard Fox|Product Management|134493|Carolyn Carter|Engineering|83664|Benjamin Brown|Business Development|73865|Diana Fisher|Services|10419什么是 DISTINCTSELECT DISTINCT用于从结果中消除重复行。最简单的用法是例如获取一个不重复的部门列表haki# SELECT DISTINCT department FROM employee;department--------------------------Services Support Training Accounting Business Development Marketing Product Management Human Resources Engineering Sales ResearchandDevelopment Legal计算机科学的学生们我知道这没有规范化……我们可以用GROUP BY做同样的事情SELECTdepartmentFROMemployeeGROUPBYdepartment;但我们现在讨论的是DISTINCT。DISTINCT ON一个经典的面试题是找出每个部门中薪水最高的员工。这是大学里教的方法haki# SELECT*FROMemployeeWHERE(department,salary)IN(SELECTdepartment,MAX(salary)FROMemployeeGROUPBYdepartment)ORDERBYdepartment;id|name|department|salary--------------------------------------------------------30|Sara Roberts|Accounting|138454|Benjamin Brown|Business Development|73863|Carolyn Carter|Engineering|836620|Janet Hall|Human Resources|282614|Chris Phillips|Legal|370610|James Cunningham|Legal|370611|Richard Bradley|Marketing|112722|Richard Fox|Product Management|1344925|Evelyn Rodriguez|ResearchandDevelopment|1062817|Benjamin Carter|Sales|619724|Jessica Elliott|Services|145427|Bonnie Robertson|Support|126748|Jean Bailey|Training|13230法律部门有两个员工薪水相同。根据不同的使用场景这个查询可能会变得相当棘手。如果你是早几年毕业的已经对数据库有所了解并且听说过分析函数和窗口函数你可能会这样做WITHranked_employeesAS(SELECTROW_NUMBER()OVER(PARTITIONBYdepartmentORDERBYsalaryDESC)ASrn,*FROMemployee)SELECT*FROMranked_employeesWHERErn1ORDERBYdepartment;结果一样但没有重复项rn | id | name | department | salary ------------------------------------------------------------ 1 | 30 | Sara Roberts | Accounting | 13845 1 | 4 | Benjamin Brown | Business Development | 7386 1 | 3 | Carolyn Carter | Engineering | 8366 1 | 20 | Janet Hall | Human Resources | 2826 1 | 14 | Chris Phillips | Legal | 3706 1 | 11 | Richard Bradley | Marketing | 11272 ...直到现在这都是我会采用的方法。接下来是真正的亮点PostgreSQL 有一个特殊的非标准子句用于查找组中的第一行SELECTDISTINCTON(department)*FROMemployeeORDERBYdepartment,salaryDESC;这太厉害了这太厉害了这太厉害了为什么从来没人告诉我这也可以文档中解释了DISTINCT ONSELECT DISTINCT ON ( 表达式 [, …] )会保留每一组这些表达式计算结果相等的行中的第一行。而我之前没听说过它的原因是非标准子句DISTINCT ON ( … )是 SQL 标准的扩展。PostgreSQL 为我们完成了所有繁重的工作。唯一的要求是我们必须按分组的字段这里是department进行ORDER BY。它还支持按多个字段进行分组这使得这个子句更加强大。IS DISTINCT FROM在 SQL 中比较值可能产生三种结果true、false或unknownWITHtAS(SELECT1ASa,1ASbUNIONALLSELECT1,2UNIONALLSELECTNULL,1UNIONALLSELECTNULL,NULL)SELECTa,b,abasequalFROMt;a|b|equal-------------------1|1|t1|2|fNULL|1|NULLNULL|NULL|NULL使用等号比较NULL和NULL的结果是UNKNOWN在表中标记为NULL。在 SQL 中1 1成立NULL IS NULL也成立但NULL ! NULL不成立。意识到这个细微差别很重要因为比较可能为空的字段可能会产生意想不到的结果。比较可能为空的字段时要得到true或false的完整条件是(aisnullandbisnull)or(aisnotnullandbisnotnullandab)结果是a | b | equal | full_condition ----------------------------------- 1 | 1 | t | t 1 | 2 | f | f NULL | 1 | NULL | f NULL | NULL | NULL | t这是我们想要的结果但太冗长了。有更好的方法吗PostgreSQL 实现了 SQL 标准用于安全地比较可为空的字段haki# SELECTa,b,abasequal,aISDISTINCTFROMbASis_distinct_fromFROMt;a|b|equal|is_distinct_from-------------------------------------1|1|t|f1|2|f|tNULL|1|NULL|tNULL|NULL|NULL|fPostgreSQL 维基上解释了IS DISTINCT FROMIS DISTINCT FROM和IS NOT DISTINCT FROM…… 将NULL视为一个已知的值而不是未知的特殊情况。好多了——既简短又清晰。其他数据库如何处理这个MySQL有一个特殊的运算符功能类似。Oracle提供了一个名为LNNVL的函数来比较可为空的字段祝你好运……。MSSQL找不到类似的函数。ARRAY_AGG (DISTINCT)当我还从 Oracle 迁移时ARRAY_AGG是 PostgreSQL 的主要卖点之一。ARRAY_AGG将值聚合成一个数组haki# SELECTdepartment,ARRAY_AGG(name)ASemployeesFROMemployeeGROUPBYdepartment;department|employees-----------------------------------------------------------Services|{Diana Fisher,Jessica Elliott} Support|{Bonnie Robertson} Training|{Jean Bailey} Accounting|{Phillip Reynolds,Sean Franklin} Business Development|{Benjamin Brown,Brian Hayes} Marketing|{Richard Bradley,Arthur Moreno} Product Management|{Richard Fox,Randy Wells} Human Resources|{Janet Hall} Engineering|{Carl Frazier,Carolyn Carter} Sales|{Benjamin Carter} ResearchandDevelo..|{Donna Reynolds,Ann Boyd} Legal|{James Cunningham,George Hanson}我发现ARRAY_AGG主要在命令行界面CLI中用于快速查看数据或者与 ORM 一起使用时很有用。PostgreSQL 更进一步也为这个聚合函数实现了DISTINCT选项。使用DISTINCT我们可以例如快速查看每个部门中不重复的薪水haki# SELECTdepartment,ARRAY_AGG(DISTINCTsalary)ASsalariesFROMemployeeGROUPBYdepartment;department|salaries-----------------------------------------Accounting|{11203} Business Development|{2196,7386} Engineering|{1542,3052} Human Resources|{2826} Legal|{1079,3706} Marketing|{5740} Product Management|{9101,13449} ResearchandDevelopment|{6451,10628} Sales|{6197} Services|{2119} Support|{12674} Training|{13230}我们可以立即看到支持部门的所有员工薪水相同。其他数据库如何处理这个MySQL有一个类似的函数叫做GROUP_CONCAT。https://dev.mysql.com/doc/refman/5.6/en/group-by-functions.html#function_group-concatOracle有一个聚合函数叫做ListAgg。它不支持DISTINCT。Oracle 在 11.2 版本中引入了这个函数在此之前互联网上充满了自定义实现。https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030MsSQL我发现最接近的是一个叫做STUFF的函数它接受一个表达式。https://docs.microsoft.com/en-us/sql/t-sql/functions/stuff-transact-sql结语本文的要点是你应该经常回归基础