教大家一种不用VBA, 不用写Sql语句就能对Excel进行一对多联表查询的方法

kinuyツ-avatar

kinuyツ

2022-04-25T16:29:55+00:00

Excel, ppt, Word 都属于微软的产品, 大多用在Windows操作系统. 对Excel的高级操作, 特别是连表操作, 大多数人会用VBA. 然而VBA是20年前的产物, VB语言也在十几年前停止了维护, 连他的儿子VB.Net 也在去年停止了维护, VB可以说已经寿终正寝了. 对于VBA, 微软也有以C# 为开发语言的VSTO作为替代.

微软主推的编程语言是C# . C# 是完全的面向对象的语言, 也可以与C++联合编程, 也可以启动Unsafe模式操作指针, 和Java有90%的语法相似度. C# 不仅可以做Web, 硬件, 工控上位机, 桌面, 做很多小工具也效果拔群, 今天我就来教大家如何用Windows窗体 做一个 Excel 一对多, 联表查询的案例.


1, 需求:

现在有2个表

表1:

[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-iznuK16T1kSbn-7n.jpg[/img]

表2:
[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-6v1fK15T1kSa2-8i.jpg[/img]


现在有6名选手参加了电子竞技比赛, 有人夺冠, 有人落榜. 现在要筛选出表1中的选手资料, 筛选条件是 表2中夺冠次数>1, 且夺冠项目中含有"魔兽" 字样.

如果用VBA, 势必要写Sql语句, 各种内连接, 外连接, 说实话复杂的sql语句我也不会. 但是C# 下有很多非常好用的ORM, 比如sqlsugar, 就是一款轻量级的ORM, 只需要linq, 按几下tab 就出来查询结果了.

在这里我用Windows窗体做了一个小程序, 我会在稍后放在某度网盘分享给大家.


2, 思路:

使用NPOI将 Excel以DataTable的格式读入winform
使用sqlsugar 使用codeFirst生成数据库(sqlite是轻量级数据库,几Kb且无需安装)
使用sqlsugar将Excel的数据存入sqlite.
使用hasmap/dictionary生成外键
使用sqlsugar进行一对多查询
使用NPOI将查询的结果导出到excel

关键Nuget包: System.Sqlite, sqlsugar, NPOI, Newtonsoft.Json

3, 过程:

选择Excel的Sheet数量(我是2个Sheet), 点击生成数据库


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-f0w3KmT1kSfe-8q.jpg[/img]

点击读取Excel(此时需要关闭你需要导入的Excel)


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-jt7fK1bT1kSfe-av.jpg[/img]



选中, 提示导入成功


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-51zqKmT1kSfe-ba.jpg[/img]


点击插入数据库


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-kvhfKtT1kSfe-e7.jpg[/img]


点击生成外键:
可以看到外键生成成功了


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-fb5uK18T1kSfe-8f.jpg[/img]


点击一对多查询, 右边的DateGridView已经显示出筛选结果了, 满足夺冠次数大于1, 且项目中包含"魔兽"字样的选手为


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-8i8iK23T3cSys-m5.jpg[/img]


4, 导出到Excel


[img]https://img.nga.178.com/attachments/mon_202205/02/-vabhQ17q-asjoKvT1kSbp-8b.jpg[/img]


其中, 用的核心 lambda表达式为

Db.Queryable<选手表>()
.Includes(p => p.项目表)
.Where(p=>p.项目表.Count()>1)
.Where(p => p.项目表.Any(z => z.夺冠项目.Contains("魔兽")))
.ToDataTable();

完全不用写SQL, 只用对应逻辑, 按Tab即可
kinuyツ-avatar

kinuyツ

链接:[url]https://pan.baidu.com/s/1OkiXk_aBXvAwt4RSirEhcw[/url]
提取码:ir6t

我做的程序的源代码.

其中Test2 是测试用的表格
Anklebully_246-avatar

Anklebully_246

虽然但是,这不是表1加一列是否夺冠检查然后用iferror检查一下就行的事情吗,为啥要搞那么复杂
kinuyツ-avatar

kinuyツ

[quote][pid=607489807,31724505,1]Reply[/pid] Post by [uid=42274775]TimeStandsStill[/uid] (2022-05-02 00:54):

虽然但是,这不是表1加一列是否夺冠检查然后用iferror检查一下就行的事情吗,为啥要搞那么复杂[/quote]如果是5个表,10个表,20个表的一对多,多对多查询呢?这只是抛砖引玉。用数据库的orm降维打击Excel
Anklebully_246-avatar

Anklebully_246

Reply to [pid=607489998,31724505,1]Reply[/pid] Post by [uid=8694089]满天星莹[/uid] (2022-05-02 00:55)

5个 20个是你临时编的吧。哪个公司那么菜会需要那么多数据库来存高相关的数据。而且真要20个数据库直接上SQL甚至Access不好吗,为啥要用Excel硬做应该用数据库做的事情。
手堯拿鐵-avatar

手堯拿鐵

楼里有个钢筋但我不说是谁[s:ac:茶]
pinkpowerwings-avatar

pinkpowerwings

说实话学linq还不如直接学sql,linq这玩意怎么说呢,略畸形,能学会lambde表达式就足够了
ChowaceSWED-avatar

ChowaceSWED

想法很好,不过按你的需求,2l的方法就解决了。是需求有问题么?[s:ac:哭笑]
kinuyツ-avatar

kinuyツ

[quote][pid=607496060,31724505,1]Reply[/pid] Post by [uid=53466]zucc[/uid] (2022-05-02 01:39):

说实话学linq还不如直接学sql,linq这玩意怎么说呢,略畸形,能学会lambde表达式就足够了[/quote]其实我用的就是lambda表达式。c# 的lambda表达式几乎和Java一模一样,只是->换成了=>

只是觉得c#做界面和工具容易,不用写SQL和VBA就能实现复杂的增删改查,只用按tab选择就行了很方便,而且sqlite碾压Access,而且是开源免费。用vsto还能开发很多Excel相关都插件,就拿出来分享一下。觉得不好请略过不看
Brokenpaper-avatar

Brokenpaper

求助一个问题,怎么引用“不存在”的表。比如其他部门每天给我发一个按日期命名的表,我需要每天把别人发来的表更新到汇总表里。有办法不通过vba实现这种功能吗?现在找到一个笨办法就是这个月引用上个月的日期的表,每天新表出来了就全部替换,但是觉得还是不够简单。
kinuyツ-avatar

kinuyツ

[quote][pid=607496233,31724505,1]Reply[/pid] Post by [uid=60358069]shinjinew[/uid] (2022-05-02 01:40):

想法很好,不过按你的需求,2l的方法就解决了。是需求有问题么?[s:ac:哭笑][/quote]我不太懂2楼的方法。如果有200个项目,要筛选出夺冠15-30项冠军,而且里面必须有魔兽争霸的选手资料,二楼的方法也能轻易实现吗? 用我的方法只用把.count()>0 改成.count()>15 &&.count()<30 && contains(“魔兽争霸”)就可以了。。。
kinuyツ-avatar

kinuyツ

[quote][pid=607496793,31724505,1]Reply[/pid] Post by [uid=42728306]不了描述的男人[/uid] (2022-05-02 01:45):

求助一个问题,怎么引用“不存在”的表。比如其他部门每天给我发一个按日期命名的表,我需要每天把别人发来的表更新到汇总表里。有办法不通过vba实现这种功能吗?现在找到一个笨办法就是这个月引用上个月的日期的表,每天新表出来了就全部替换,但是觉得还是不够简单。[/quote]按照发给你的表的表名,做一个class,然后读取,然后按照时间update进去就行了
DrToe-avatar

DrToe

插眼……
虽然我可能用不上,但是楼主好人一生平安。
inquiz-avatar

inquiz

其实尴尬在
对于有语言/数据库基础的人来说lz教不教也会 只是用不用的到

对于没有语言基础的人来说,一个无法验错,只能信或者不信。因为在不懂语言的情况下lz的工具对使用人来讲是黑箱,比如我就不知道lz说的外键是什么。另外一个,需求有变更的话,他自己也不会写。


最后如果实在需要一个工具的话,推荐一个 “excel必备工具箱”安装后是嵌入到excel/wps里的,很多实用的功能。比如就有lz说的一对多查询。
Chrissy-avatar

Chrissy

直觉告诉我数据透视图也能实现需求[s:ac:瞎]
Goldn-avatar

Goldn

楼主你数据都进内存了,为啥还要sqlite一下啊[img]https://img.nga.178.com/attachments/mon_201209/14/-47218_5052bc4cc6331.png[/img]
Longswording 壁-avatar

Longswording 壁

感谢楼主分享,虽然我用不到不过有一说一,这种不明软件没几个人敢往公司机器上拷,建议换成代码,然后自己封装
wolferkills23-avatar

wolferkills23

用适合的工具做适合的事,SQL还是得学
不过百M以内的数据,python全读内存里暴力操作应该是最省事的
kinuyツ-avatar

kinuyツ

[quote][pid=607499568,31724505,1]Reply[/pid] Post by [uid=150172]zzzzv[/uid] (2022-05-02 02:12):

用适合的工具做适合的事,SQL还是得学
不过百M以内的数据,python全读内存里暴力操作应该是最省事的[/quote]sql最麻烦的是,一个字符串写错了,很难去调试和找出错误。而且SQL语句越长,越容易出错。否则为什么在switch语句中,条件判断都用来枚举,就是为了降低错误概率。而且SQL语句还容易被SQL注入,非常不安全
wolferkills23-avatar

wolferkills23

楼主看看pandas和jupyter,发现新天地
c#就不是干这种事用的,启动宇宙第一ide的功夫别人都写完了