C#代码中实现两个表(DataTable)的关联查询(JOIN)
之前通常都是使用SQL直接从数据库中取出表1和表2关联查询后的数据,只需要用一个JOIN就可以了,非常方便。近日遇到一种情况,两个表中的数据已经取到代码中,需要在代码中将这两个表关联起来,并得到它们横向拼在一起之后的完整数据。
如:表1--商品信息表(dtHead),存放商品的ID和名称,表结构和数据如下:
表2--商品数量及金额表(dtTail),存放商品的数量、金额,表结构和数据如下:
现在要得到表1和表2横向拼接起来的表(DtAll),结果如下:
在C#代码中,要将这两个表拼接起来,有很多笨办法,例如循环获取数据一条条拼起来,但在数据量大的情况下会影响性能,在字段多的时候也需要写一大堆给每个字段依次赋值的代码。
使用LINQ可以帮助解决这一问题。下面提供了两种方案:
方案一:当能够确定DtAll表的字段,并且字段不是很多的情况下,可以显式写出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var query1 = from rHead in dtHead.AsEnumerable() from rTail in dtTail.AsEnumerable() where rHead.Field<Int32>( "GoodID" ) == rTail.Field<Int32>( "GoodID" ) select new { GoodID = rHead.Field<Int32>( "GoodID" ), GoodName = rHead.Field<String>( "GoodName" ), Num = rTail.Field<Int32>( "Num" ), Money = rTail.Field<Int32>( "Money" ) }; DataTable dtNew = DtAll.Copy(); foreach ( var obj in query1) { dtNew.Rows.Add(obj.GoodID, obj.GoodName, obj.Num, obj.Money); } |
其中DtAll的表结构已经事先创建好了,在下面会给出所有代码。
方案二:LINQ提供了与SQL中类似的JOIN方法。并且当字段很多的情况下,每一个字段都在select new中写出来比较麻烦,可以使用如下的方式:
1 2 3 4 5 6 7 8 9 10 11 12 | var query = from rHead in dtHead.AsEnumerable() join rTail in dtTail.AsEnumerable() on rHead.Field<Int32>( "GoodID" ) equals rTail.Field<Int32>( "GoodID" ) select rHead.ItemArray.Concat(rTail.ItemArray.Skip(1)); foreach ( var obj in query) { DataRow dr = DtAll.NewRow(); dr.ItemArray = obj.ToArray(); DtAll.Rows.Add(dr); } |
使用Concat将表1和表2的字段拼接起来,作为总表DtAll的字段,但由于表1、表2中都存在字段GoodID,不能在表中出现重复的字段,因此使用Skip(1)跳过表2中的第一个字段GoodID。
下面给出这个小例子完整的代码(不包括窗体,窗体上很简单,只有一个按钮)
首先写入测试数据:把表1、表2创建起来并插入如上图所示的数据(实际情况是表1、表2通过其他渠道直接获取到代码中的)
然后在单击“连接”按钮时,得到表1、表2横向连接后的表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Data; namespace WpfApplication1 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { DataTable dtHead = new DataTable(); DataTable dtTail = new DataTable(); DataTable DtAll = new DataTable(); public MainWindow() { InitializeComponent(); this .AddData(); } /// <summary> /// 创建表结构,添加数据源 /// </summary> private void AddData() { dtHead.Columns.Add( "GoodID" , typeof (Int32)); dtHead.Columns.Add( "GoodName" , typeof (String)); dtTail.Columns.Add( "GoodID" , typeof (Int32)); dtTail.Columns.Add( "Num" , typeof (Int32)); dtTail.Columns.Add( "Money" , typeof (Int32)); DtAll.Columns.Add( "GoodID" , typeof (Int32)); DtAll.Columns.Add( "GoodName" , typeof (String)); DtAll.Columns.Add( "Num" , typeof (Int32)); DtAll.Columns.Add( "Money" , typeof (Int32)); this .AddRow(1, "青岛纯生" , 10, 30); this .AddRow(2, "哈尔滨啤酒" , 5, 20); } /// <summary> /// 添加数据 /// </summary> /// <param name="goodID"></param> /// <param name="goodName"></param> /// <param name="num1"></param> /// <param name="num2"></param> private void AddRow(Int32 goodID, String goodName, Int32 num1,Int32 num2) { DataRow drH = dtHead.NewRow(); drH[ "GoodID" ] = goodID; drH[ "GoodName" ] = goodName; dtHead.Rows.Add(drH); DataRow drT = dtTail.NewRow(); drT[ "GoodID" ] = goodID; drT[ "Num" ] = num1; drT[ "Money" ] = num2; dtTail.Rows.Add(drT); } /// <summary> /// “连接”按钮单击事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_Join_Click( object sender, RoutedEventArgs e) { //方案一 var query1 = from rHead in dtHead.AsEnumerable() from rTail in dtTail.AsEnumerable() where rHead.Field<Int32>( "GoodID" ) == rTail.Field<Int32>( "GoodID" ) select new { GoodID = rHead.Field<Int32>( "GoodID" ), GoodName = rHead.Field<String>( "GoodName" ), Num = rTail.Field<Int32>( "Num" ), Money = rTail.Field<Int32>( "Money" ) }; DataTable dtNew = DtAll.Copy(); foreach ( var obj in query1) { dtNew.Rows.Add(obj.GoodID, obj.GoodName, obj.Num, obj.Money); } //方案二 var query = from rHead in dtHead.AsEnumerable() join rTail in dtTail.AsEnumerable() on rHead.Field<Int32>( "GoodID" ) equals rTail.Field<Int32>( "GoodID" ) select rHead.ItemArray.Concat(rTail.ItemArray.Skip(1)); foreach ( var obj in query) { DataRow dr = DtAll.NewRow(); dr.ItemArray = obj.ToArray(); DtAll.Rows.Add(dr); } } } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
2015-10-11 SQL Delta实用案例介绍,很好的东西,帮了我不少忙