针对distinct疑问引发的一系列思考

 更新时间:2015年11月09日 10:15:58   作者:陈希章  
这篇文章主要针对distinct疑问引发的一系列思考,希望大家耐心阅读,一定会有所收获。

有人提出了这样一个问题,整理出来给大家也参考一下

假设有如下这样一张表格:

这里的数据,具有如下的特征:在一个DepartmentId中,可能会有多个Name,反之也是一样。就是说Name和DepartmentId是多对多的关系。

现在想实现这样一个查询:按照DepartmentID排完序之后(第一步),再获取Name列的不重复值(第二步),而且要保留在第一步后的相对顺序。以本例而言,应该返回三个值依次是:ACB

我们首先会想到下面这样一个写法

select distinct name from Sample order by DepartmentId

从语义上说,这是很自然的。但是很可惜,这个语句根本无法执行,错误消息是:

这个错误的意思是,如果使用了DISTINCT(去重复值),则出现在OrderBy后面的字段,必须也出现在SELECT后面,但如果DepartmentID如果也真的出现在SELECT后面,显然是不会有重复值的,所以结果肯定也是不对的。

select distinct name,DepartmentId from Sample order by DepartmentId


 

那么,既然DISINCT 与OrderBy结合起来用会有这个的一个问题,我们是否有可能变通一下,例如下面这样:

SELECT distinct a.Name
FROM (select top 100 percent name from Sample order by DepartmentId) a

想比较之前的写法,我们用到了子查询技术。同样从语义上看,仍热是很直观明了的。我想先按照DepartmentId进行排序, 然后再去重复值。但是返回到结果是下面这样的:

虽然确实去除了重复值,但返回的顺序却是不对的。我们希望是先按照DepartmentId排序之后,然后去除重复值,并且保留排序后的相对顺序。

为什么会出现上面这个结果呢?其实是因为DISTINCT本身是会做排序的,而且这个行为是无法更改的(下图的执行计划中可以看到这一点)。所以其实我们之前做的Order by在这里会失去意义。【实际上,如果观察ADO.NET Entity Framework等ORM工具中生成的类似的一个查询,它会自动丢弃Order by的设置】

那么,这样的情况下,是不是就不可能实现需求了呢?虽然说,这个需求并不多见,绝大部分时候,DISTINCT作为最后一个操作,做一次排序是合乎情理的。

我是这样考虑到,既然DISTINCT的这个行为是内置的,那么是否可以绕过这个操作呢?最终我用的一个解决方案是:我能不能把每个Name都编上一个编号,例如有两个A的话,第一个A我为它编号为1,第二个编号为2,以此类推。然后,查询的时候,我先排序,然后筛选那些编号为1的Name,这样其实也就实现了去重复值了。

SQL Server 2005开始提供了一个ROW_NUMBER的功能,结合这个功能,我实现了下面这样的查询:

select a.Name from 
(select top 100 percent
Name,DepartmentId,ROW_NUMBER() over(partition by name order by departmentid) row
from Sample order by DepartmentId) a
where a.row=1
order by a.DepartmentId

然后,我得到了下面这样的结果,我推敲下来,这应该是符合了之前提到的这个需求的

相比较而言,这个查询的效率会低一些,这个是可以预见的(可以通过下图看出一点端倪)。但如果需求是硬性的,那么牺牲一些性能也是不奇怪的。当然,我们可以再研究看看是否有更优的一些写法。无论如何,使用内置标准的实现,通常都是相对较快的。

以上就是关于distinct疑问引发的一系列思考,希望对大家的学习有所帮助。

相关文章

  • delete from 表名与truncate table 表名区别

    delete from 表名与truncate table 表名区别

    delete from 表名与truncate table 表名区别,选择适合我们的删除数据库数据的方法
    2012-10-10
  • 基于SSIS 事件的向上传递(详解)

    基于SSIS 事件的向上传递(详解)

    下面小编就为大家分享一篇基于SSIS 事件的向上传递(详解),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • SQL Server允许重复空字段不空字段值唯一

    SQL Server允许重复空字段不空字段值唯一

    今天同学向我提了一个问题,我觉得蛮有意思,现记录下来大家探讨下。问题是:在一个表里面,有一个允许为空的字段,空是可以重复的,但是不为空的值需要唯一。
    2011-03-03
  • SQL server 中 CROSS APPLY的使用及用途

    SQL server 中 CROSS APPLY的使用及用途

    CROSS APPLY是SQL Server中的操作符,用于将表表达式与外部表连接,它允许在查询中多次引用外部表的行,并根据每行动态生成结果集,而OUTER APPLY则类似于LEFT JOIN,后者即使子查询无结果也会显示外部表的行,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • T-SQL篇如何防止SQL注入的解决方法

    T-SQL篇如何防止SQL注入的解决方法

    所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令,对于这种行为,我们应该如何制止呢?本文将介绍一种方法,希望可以帮助有需要的朋友
    2012-11-11
  • SQL Server Alwayson创建代理作业的注意事项详解

    SQL Server Alwayson创建代理作业的注意事项详解

    在工作中有时为了避免数据库增长太大所以需要定时来删除某段时间前的数据,所以使用代理作业的方式来实现定时删除的功能,下面这篇文章主要给大家介绍了关于SQL Server Alwayson创建代理作业的注意事项,需要的朋友可以参考下。
    2017-09-09
  • 揭秘SQL Server 2014有哪些新特性(1)-内存数据库

    揭秘SQL Server 2014有哪些新特性(1)-内存数据库

    微软SQL Server 2014提供了众多激动人心的新功能,但其中最让人期待的特性之一就是代号为” Hekaton”的内存数据库了,内存数据库特性并不是SQL Server的替代,而是适应时代的补充,现在SQL Server具备了将数据表完整存入内存的功能。那么今天我们就先来看看内存数据库
    2014-08-08
  • 为数据库生成某个字段充填随机数的存储过程

    为数据库生成某个字段充填随机数的存储过程

    为数据库生成某个字段充填随机数
    2010-05-05
  • 整理一下SQLSERVER的排序规则

    整理一下SQLSERVER的排序规则

    整理一下SQLSERVER的排序规则...
    2006-09-09
  • SQL语句查询数据库中重复记录的个数

    SQL语句查询数据库中重复记录的个数

    一个sql语句:一个表test有四个字段id,a,b,c,如果表中的记录有三个字段a,b,c都相等,则说明这条记录是相同的,求相同的记录的个数 。
    2009-11-11

最新评论