星星之火

燎原之势不可挡
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

2013-4-29

DataTable中如何去除重复的项

上周在项目中遇到一个问题,就是获取DataTable中某一列的值,因为从数据库中检索数据时,按照2个字段进行分组,而要获得的那一列刚好在分组这两列中,所以该列的值必然有重复,于是就想到了去除重复,有了思路以后在网上看了一些方法,大都是遍历之类的,虽说功能是可以实现,但是效率太低了,最后发现了一个简单的方法,如下:

public string[] GetNamesFromDataTable(DataTable dataTable)
        {
            DataView dv = dataTable.DefaultView;
            dataTable = dv.ToTable(true, "Name");
            string[] names = new string[dataTable.Rows.Count];
            for (int i = 0; i < names.Length; i++)
            {
                names[i] = dataTable.Rows[i][0].ToString();
            }
            return names;
        }

  

解析:DataView.ToTable()方法有四个重载方法,分别如下:

      ToTable():根据现有的DataView中的行,创建并返回一个新的DataTable

      ToTable(string tableName):功能如上,只不过是为新的DataTable赋了一个名字

      ToDataTable(bool distinct,parm string[] columnNames):根据现有的DataView中的行创建并返回DataTable,distinct,为true,则返回所有列都具有不同值的行,第二个参数为一个字符数组,即可以指定要获取的列,上边的例子中,只指定了一列,即获取某一列的不重复的信息。

      ToDataTable(string tableName,bool distinct,parm string[] columnNames);功能如上,只不过多了一个DataTableName

SQL中的Join 问题

上周在项目中遇到一个这样的问题,通过关联两个表进行数据的查询,然后按照两个字段进行分组,整个查询逻辑是没有问题的,但是查询结果总是所有的分组项的值都是一样的,而事实上查询的结果应该是不同的,而且有些分组项是没有值的,这个时候检查了一下SQL语句,发现在进行两表关联的时候是进行等值连接,也就是内连接的一种表示形式。如果想要得到想要的结果,应该是以其中的一个表为主表进行左连接或右连接的。既然讲到了这里就把SQL的各种连接再温习一遍。

这里我把连接分为三类,内连接、外连接和交叉连接。当然还有其他的分类方法,但大体上都是一样的。下面对各种连接一一进行分析。

在开始分析之前,先建两个临时的表作为演示示例。

create table #T1(id int, name varchar(20))
create table #T2(rootid int, value int)
insert into #T1 values(116,'Olive')
insert into #T1 values(224,'Only')
insert into #T1 values(336,'For')
insert into #T1 values(448,'You')
insert into #T1 values(1115,'Love')
insert into #T2 values(116,1)
insert into #T2 values(224,3)
insert into #T2 values(336,1)
insert into #T2 values(448,4)
insert into #T2 values(1165,24)

  

内连接

以下这两种方式都是内连接的表示形式

1)       内连接的简单形式

select t1.name as Name,t2.value as Value from #T1 t1,#T2 t2 where t1.id=t2.rootid

2)       内连接的标准形式

select t1.name as Name ,t2.value as Value from #T1 t1 inner join #T2 t2

on t1.id=t2.rootid

结果:                        

PS:

也有将内连接称之为等值连接的,就像上边讲到的第一种形式那样。还有一点需要注意的是如果内连接没有连接条件的话和笛卡尔积的交叉连接结果是一样的,但是效率要比笛卡尔积的效率要高。

关于等值连接和自然连接,等值连接是上边讲的第一种形式,而=号则用于连接条件,不会去除重复,自然连接的话,不会有重复的行存在。

外连接

外连接是区分于内连接而言的。外连接又可以分为左外连接和右外连接。

左外连接

select t1.name as Name,t2.value as Value from #T1 t1 left outer join #T2 t2 on t1.id=t2.rootid

结果: 

右外连接

select t1.name as Name,t2.value as Value from #T1 t1 right outer join #T2 t2 on t1.id=t2.rootid

结果:

全外连接

select t1.name as Name,t2.value as Value from #T1 t1 full outer join #T2 t2 on t1.id=t2.rootid

结果:

PS:

     由上边的结果我们可以看出,所谓的左或者右外连接主要强调的是以哪个表为基准,左外连接就是以左边的表为基准表,如果右边的表中没有与其关联的信息,则显示为null,同样,右连接也是如此,只不过是以右边的表为基准。而全外连接则是要获取所有#T1表和#T2表的集合。

交叉连接

select * from #T1,#T2

select * from #T1 cross join #T2

结果:

PS:

      交叉连接相当于两个表的笛卡尔积,匹配一个表的每一行与另一个表的每一行,上边也有提到,如果内连接没有连接条件的话,查询的结果跟交叉连接的结果是一样的,但是事实上没有查询条件的内连接的效率要比交叉连接的效率高很多。

另:

此外在网上看到了还有Cross Play连接,即可以与一个自定义的查询函数进行连接的,但是,该连接的效率很低,而且完全可以通过内连接来实现,所以这里就不再讲了,有兴趣的朋友可以自己去了解下。