SQL点滴23—T-SQL中的除法

  

在T-SQL中没有除法运算,但是在T-SQL中可以实现类似除法的操作Divide。一般除法操作的结果一个列来自于被除关系表,剩下的来自除关系表。这里举一个例子来说明。假设如下有三个表:客户Customers,销售人员Employees,订单Orders,查询返回一些客户,要求这些客户和所有美国雇员都至少有一次交易记录。来看下面一个语句:

select custid from Sales.Customers as C
where not exists
(
select * from HR.Employees as E
where country='USA'
and not exists
(
select * from Sales.Orders as O
where O.custid = C.custid
and O.empid = E.empid))

  

语句返回23行,标明有23名客户,这些客户至少和每个美国雇员有一次交易记录。现在我们如果修改一下条件,问题要求还是一样的,我们把销售人员的国家修改成以色列Israel,看看以色列的销售人员是否能像美国雇员一样的强悍。

  

select custid from Sales.Customers as C
where not exists
(
select * from HR.Employees as E
where country='Israel'
and not exists
(
select * from Sales.Orders as O
where O.custid = C.custid
and O.empid = E.empid))

  

修改国家条件,这次我们查询得到的结果是91条记录,我们看看Customers这个表总共也就91条记录,很明显这个结果不对。我们使用语句来看看select * from Sales.Customers where country like '%Israel%',查询得到0条记录,就是说根本就没有以色列的雇员。因为没有来自以色列的雇员,所有雇员和该客户拥有至少一项交易记录这个条件对每个雇员都满足,这个是代数里面的空真现象。换句话说每个客户都和这个不存在的以色列雇员至少有一项交易记录。这个很像除法运算的一个规则:除数是0,商就是无限大

  
写上面的语句的时候,我们没有考虑如果Employee表中没有如果没有以色列的雇员怎么办。如果我们在问题中加上确实存在来自以色列的雇员就可以避免这个错误,只需要在条件中限定至少有一个以色列雇员存在于表Employee中就可以了。这个就像除法中的非0限定:除数不为0。语句如下:

  

select custid from Sales.Customers as C
where not exists
(
select * from HR.Employees as E
where country='Israel'
and not exists
(
select * from Sales.Orders as O
where O.custid = C.custid
and O.empid = E.empid))
and exists (select * from HR.Employees as E where country='Israel')

现在查询得到0条结果,这才是我们想要的。

  
在这个除法操作中有三个关系,a Divide by b Per c,a是被除数,b是除数,c是中介关系。假设a有属性A,b有属性B。在上面的语句中被除关系是Customers,除数关系是满足一定关系的Employee,中介关系是Orders。这里为了避免除数是0 的问题,使用第四个临时关系(select * from HR.Employees as E where country='Israel')。也可以使用另外一种方法来限定至少有一名以色列的销售人员和所有顾客至少有一次交易记录。如下:
a,找到美国雇员的id:select empid from HR.Employees where country='USA',这个语句找到的是(1,2,3,4,8)。
b,找到美国雇员的数量:select COUNT(*) from HR.Employees where country='USA',很明显这个找到的结果是5。
c,根据雇员id查找交易记录表中的客户id,并按客户id分组,在分组中查找不重复的empid数目等于5的。

  

select custid
from Sales.Orders
where empid in (1,2,3,4,8) group by custid having count(distinct empid)=5

  

我们把上面两个查询还原上去,由于没有以色列的雇员,还是使用美国雇员:

select custid
from Sales.Orders
where empid in
(
select empid from HR.Employees where country = N'USA')
group by custid
having count(distinct empid) = (select count(*) from HR.Employees where country = N'USA')

查询得到的结果是23条记录,符合我们的要求。


 

posted @ 2011-09-02 14:13  nd  阅读(8006)  评论(3编辑  收藏  举报