高难度的SQL查询语句。。。。(100分)

  • 主题发起人 主题发起人 t163t163
  • 开始时间 开始时间
T

t163t163

Unregistered / Unconfirmed
GUEST, unregistred user!
本人在做人力系统,建立了几个关联表,结构如下:
1、NOWEMP id(系统编号),A02(中文姓名),A10(身份证)。。。。。
2、MESS id(NOWEMP 中的id号),M03(联系电话)。。。。。。
3、SKILL id(NOWEMP 中的id号),A10(技能项目)。。。。。。
4、CONTRACT id(NOWEMP 中的id号),A03(合同开始日期)。。。。。
现在,我想让用户能任意的查询,例如:
想查符合以下条件的员工:合同开始日期在“2000/01/01”之前,并且技能项目为“英语”
或者 (技能项目为“日语”并且 联系电话为“12345678”)
请问类似这种让用户能任意的查询的查询模块该如何编写呢?
 
可不可以这样:
adoquery1.close;
adoquery1.sql.add('
select a.*,b.m03,c.a10,d.a03 from NOWEMP a,MESS b,SKILL c,CONTRACT d
where b.id=a.id and c.id=a.id and d.id=a.id');
//如果按合同开始日期查询
adoquery1.sql.add('and d.a03>=:rq');
//其他的条件诸如此类
 
呵呵。手先在纸上画画。
就很清楚了
 
adoquery1.close;
adoquery1.clear;
adoquery1.sql.add(
'select a.id,a.a01,a.a10,b.m03,c.a10 from NOWEMP a,MESS b,SKILL c,CONTRACT d
where d.id=a.id and d.id=b.id and d.id=c.id');
if EditDate1.Text <> '' then
adoquery1.sql.add(' and d.a03>=''' + EditDate1.Text + '''');
if EditSkill.text <> '' then
...........

 
各位,其实你们误会了,
例如:
1、NOWEMP 中的数据:
系统编号 中文姓名 身份证
1 a 123456789
2 b 。。。。
3 c 。。。。。
2、MESS 中的数据:
ID M03
2 12345678
3 456
3、SKILL 中的数据
ID A10
1 英语
3 日语
4、 CONTRACT 中的数据
ID A03
2 1999/01/01
1 2000/01/01

条件:合同开始日期在“2000/01/01”之前 或者 技能项目为“日语”,如果
按各位的查询方式必然会与用户的结果相反。请问该如何呢?
 
首先,觉得你这样分解数据表,可能不好,一般习惯是这几个表合在一个表中间。
但是,我想你的这样划分是有目地的,目的是在不同的内容中存储多个项目,一个表,无法做到。
这样划分表,也还过得去,不过在查询的时候,大大增加了SQL语句的难度。
但是你的合同表绝对应该与第一个NOWEMP表合在一起,因为,一个人,只能有一条合同记录,不可能有两条合同记录的。
如果想保留员工的合同记录,那也之是历史合同记录表。这样合并记录后,查询多少要简单很多。
估计只能使用嵌套查询才能满足你的要求。

首先分析下:如果对同一个表,只提供一个查询条件,还很好办。
如果是多个条件,例如,对技能表,同时查询员工技能有“英语”和“日语”两项的话,SQL语句就很麻烦了。
如果要写的话:
select Nowemp.id,nowemp.A02
from nowemp inner join skill on skill.id = nowemp.id
where skill.a10='日语' and skill.id in (select id where from skill where a10='英语')

如果是查询条件为员工技能为“英语”或“日语”的话要这么写:
select nowemp.id, nowemp.a02
from nowemp inner join skill on skill.id = nowemp.id
where skill.a10='日语'
union
select nowemp.id, nowemp.a02
from nowemp inner join skill on skill.id = nowemp.id
where skill.a10='英语'
Group by nowemp.id, nowemp.a02

总之,不管怎么样,SQL语句都必要复杂。要想做一个公用的Sql语句,几乎不可能。
如果按你的要求:
合同开始日期在“2000/01/01”之前,并且技能项目为“英语”
或者 (技能项目为“日语”并且 联系电话为“12345678”)
那么查询语句要这么写:
select nowemp.id, nowemp.a02
from skill inner join (contract inner join nowemp on contract.id = nowemp.id ) on skill.id = nowemp.id
where contract.a03 ='200/01/01' and skill.a10='英语'
union
select nowemp.id, nowemp.a02
from skill inner join (mess inner join nowemp on mess.id = nowemp.id ) on skill.id = nowemp.id
where mess.a03 ='12345678' and skill.a10='日语'
Group by nowemp.id,nowemp.a02

注意:你的条件中有个“或者”,并且或者的内容是分布在多条记录上的,所以只能采用“联合查询union”才能满足你的要求。

 
我的意见是先建立一个视图,视图就是把这几个表合在一起的,
然后从视图中查询不是简单多了吗?
 
很感谢biggo,但我还是想看看是否可以做成公用的。
Expert:对于
 
biggo说得不太正确。从数据库的角度来说,这样没有什么问题,看看设计用的范式
就知道了。NowEmp是人的信息,Contract是合同的信息, 怎么能放在一起呢? 不论
它们之间是一对一还是一对多。其一,一个表的列太多,会导致一条记录太长,导致
读的性能下降,因为读一Unit时读的记录数少了.
其实一点都不复杂,把它们做个外连接就可以了
 
将每个表分列,允许用户设定各个条件间的逻辑关系,再在程序中组合成SQL语句.
 
这难道很难吗?
'select id,a02,a10... from newemp where '
+' id in (select a.id from skill a,contract b'
+'where a.a10='英语' and b.a03 between ''1900/01/01'' and ''2001/01/01'' and a.id=b.id )'
+' or id in (select a.id from skill a,mess b '
+'where a.a10=''日语'' and b.m03=''12345678'' and a.id=b.id )'
 
建视图可能是一种比较简便的方法,要不你就得去“拼凑”SQL.
 
视图是个好办法,但是结果浏览的时候,不是有点累赘吗?
 
不知道MichaelZhu说的“结果浏览”是什么意思?!
对视图的操作就跟表一样——可以任意选取显示字段,
但是最好不要通过该视图来修改数据——单个表试图除外
 
这种还不简单,用联结即可。
select id,a02,a10... from NOWEMP left out join MESS on MESS .id=NOWEMP.id
left out join SKILL onSKILL.id=NOWEMP.id 等 where 条件
注意有些数据服务器支持的外连接个数有限制,你这么几个肯定没问题。

>>请问类似这种让用户能任意的查询的查询模块该如何编写呢?
这种看你程序的设计,不是一两句话说的清的。
 
首先我得申明,我并不反对这样建表,只是想说,这样建表给开发工作带来巨大的麻烦。
但我还是对合同表建议优化,因为一个人当前人事合同肯定只有一个,要建的话,也应该建一个历史合同表,
当前合同记录,可放到主表中,这样相对容易处理。

关于分表处理数据,最主要带来的问题是,很难做公用查询函数。如果我想做以下查询,条件只用一个DBGrid显示:
查询某员工的所有电话号码,以及所有技能,要求一个表中显示(分表显示就太容易了),大家想想看,是不是很困难。
解决的方法,只能使用存储过程。如果在客户端,只能采用其它方法模拟,效率要底很多。

既然决定采用这种建表方法,那么就必须面对编程代码成备增加的困难。必要的时候,可能还需要分成几个Sql语句查询数据,然后分别分析和汇总。

Sql语句不是万能的,如果再把上面的查询条件加复杂些,那就只能分开处理,再分析汇总。
用多几行笨代码,降低些执行速度,来换取正确的结果和避免一条SQL语句的复杂度。

最后总结下,如果你真正想做一个公用的任意查询模块,只能是采用分步查询来做,
例如问题要求:
合同开始日期在“2000/01/01”之前,并且技能项目为“英语”
或者 (技能项目为“日语”并且 联系电话为“12345678”)
先做一个查询把符合条件(合同开始日期在“2000/01/01”之前,并且技能项目为“英语”)第一个条件的记录集找出来,然后再
找第二个条件的找出来,最后合并分析得到最后结果。用牺牲效率换取公用。
想把任何查询条件都转化到一条Sql语句查询得公用查询模块,几乎不可能。
 
后退
顶部