2

我想将Informants表加入到他们对应的Handlers

 Informants                       Handlers
+------------------------+      +----------------------------------------+
|Name         Type       |      | HandlerID  Name            HandlerType |
|------------ ---------- |      |----------  ----------------------------|
|Ronald Regan Politician |      | 1          J. Edgar        FBI         |
|Sal Vitale   MOB        |      | 2          Charles Cabell  CIA         |
|Elia Kazan   Famous     |      | 3          Allen Dulles    CIA         |
|Mrs. Kravitz Citizen    |      | 7          Joe McCarthy    Congressman |
|White Pawn   Foreign    |      +----------------------------------------+
+------------------------+

我遵循的规则取决于谁来确定您可以通知的人群:

  • 政治家 --> 中央情报局
  • 黑手党和著名的名人 --> 联邦调查局
  • 普通公民 --> 当地警察局
  • 外国特工 --> 可以求助于 NSA

因此,我将告密者与他们可以通知的对象进行匹配:

SELECT 
   Informants.Name AS RatName,
   Informants.Type AS RatType,
   Handlers.Name AS GmanName,
   Handlers.HandlerID 
FROM Informants
   LEFT JOIN Handlers
   ON (
      (Informants.Type IN ('Politician') AND Handlers.HandlerType = 'CIA')
      OR  
      (Informants.Type IN ('MOB', 'Famous') AND Handlers.HandlerType = 'FBI')
      OR
      (Informants.Type IN ('Citizen') AND Handlers.HandlerType = 'Police')
      OR
      (Informants.Type IN ('Foreign') AND Handlers.HandlerType = 'NSA')
 )

我得到了结果:

RatName           RatType               GmanName        HandlerID
=============     ==============        ==============  =========
Ronald Regan      Politician            Charles Cabell  2
Ronald Regan      Politician            Allen Dulles    3
Sal Vitale        MOB                   J. Edgar        1
Elia Kazan        Famous                J. Edgar        1 
Mrs. Kravitz      Citizen               NULL            NULL
White Pawn        Foreign               NULL            NULL

您可以在此处看到Ronald Regan两个可以求助的已配置处理程序。尽管:

  • 克拉维茨夫人,和
  • 白典当

没有他们可以通知的处理程序

所以我现在想要的是处理程序的后备列表。如果您是代理PoliticianForeign代理,我们希望您回退FBI处理程序。这意味着理想情况下我的结果集将是:

RatName           RatType               GmanName        HandlerID
=============     ==============        ==============  =========
Ronald Regan      Politician            Charles Cabell  2
Ronald Regan      Politician            Allen Dulles    3
Sal Vitale        MOB                   J. Edgar        1
Elia Kazan        Famous                J. Edgar        1 
Mrs. Kravitz      Citizen               NULL            NULL
White Pawn        Foreign               J. Edgar        1

那是我的问题,我需要加入早期加入不匹配任何内容标准。


问题

我试图避免的问题是:

  • 主要案例连接PoliticiansFBI
  • 备份案例加入PoliticiansCIA

我最终是这样的:

RatName           RatType               GmanName        HandlerID
=============     ==============        ==============  =========
Ronald Regan      Politician            Charles Cabell  2
Ronald Regan      Politician            Allen Dulles    3
Ronald Regan      Politician            J. Edgar        1
Sal Vitale        MOB                   J. Edgar        1
Elia Kazan        Famous                J. Edgar        1 
Mrs. Kravitz      Citizen               NULL            NULL
White Pawn        Foreign               J. Edgar        1

罗纳德·里根(Ronald Regan)获得了一个新的“后备”条目,当时他已经有人要向他报告。

4

3 回答 3

4

我想有点晚了,但我建议:

  • 使用规范化模式
  • 使用类型的查找表并引用它们
  • 为回退规则使用多对多联结表
  • 允许许多后备选项
  • 避免将逻辑放入代码中——将其放入数据中

这是架构设置脚本:

-- Setup test data
create table InformantTypes (
    Type varchar(20) not null primary key
)
insert into InformantTypes select 'Politician'
insert into InformantTypes select 'MOB'
insert into InformantTypes select 'Famous'
insert into InformantTypes select 'Citizen'
insert into InformantTypes select 'Foreign'

create table HandlerTypes (
    Type varchar(20) not null primary key
)
insert into HandlerTypes select 'FBI'
insert into HandlerTypes select 'CIA'
insert into HandlerTypes select 'Congressman'
insert into HandlerTypes select 'Police'
insert into HandlerTypes select 'NSA'

create table InformantTypesToHandlerTypes (
      InformantType varchar(20) not null references InformantTypes (Type)
    , HandlerType varchar(20) not null references HandlerTypes (Type)
    , Ordinal int not null
)
insert into InformantTypesToHandlerTypes select 'Politician', 'CIA', 1
insert into InformantTypesToHandlerTypes select 'MOB', 'FBI', 1
insert into InformantTypesToHandlerTypes select 'Famous', 'FBI', 1
insert into InformantTypesToHandlerTypes select 'Citizen', 'Police', 1
insert into InformantTypesToHandlerTypes select 'Foreign', 'NSA', 1
insert into InformantTypesToHandlerTypes select 'Politician', 'FBI', 2
insert into InformantTypesToHandlerTypes select 'Foreign', 'FBI', 2

create table Informants (
      Name varchar(50) not null primary key
    , Type varchar(20) not null references InformantTypes (Type)
)
insert into Informants select 'Ronald Regan', 'Politician'
insert into Informants select 'Sal Vitale', 'MOB'
insert into Informants select 'Elia Kazan', 'Famous'
insert into Informants select 'Mrs. Kravitz', 'Citizen'
insert into Informants select 'White Pawn', 'Foreign'

create table Handlers (
      HandlerID int not null primary key
    , Name varchar(50) not null unique
    , HandlerType varchar(20) not null references HandlerTypes (Type)
)
insert into Handlers select 1, 'J. Edgar', 'FBI'
insert into Handlers select 2, 'Charles Cabell', 'CIA'
insert into Handlers select 3, 'Allen Dulles', 'CIA'
insert into Handlers select 7, 'Joe McCarthy', 'Congressman'

这是实际的查询(它精确地返回 OP 的输出):

-- Actual Query
;with cte as (
    select RatName, RatType, GmanName, HandlerID, DenseRank
    from (
        select
            i.Name AS RatName,
            i.Type AS RatType,
            h.Name AS GmanName,
            h.HandlerID,
            dense_rank() over (partition by i.Name order by ordinal) as DenseRank
        from Informants i
            join InformantTypesToHandlerTypes tt on i.Type = tt.InformantType
            join Handlers h on tt.HandlerType = h.HandlerType
    ) as a
    where DenseRank = 1 -- This bit keeps Reagan from going to the FBI
)
-- Get informants with their first available handler option
select RatName, RatType, GmanName, HandlerID
from cte
-- Get informants with no available handler option
union all
select i.Name, i.Type, null, null
from Informants i
where i.Name not in (select RatName from cte)
order by RatName

作为一点解释,以下是该查询的作用:

  • 就像 OP 一样,我们Informants加入Handlers基于Type. 我们只是在CTE内部进行,因为我们想轻松地多次使用它(CTE 实际上是一个临时视图,派生表、表变量或临时表可以同样轻松地工作)。
  • 我们不是根据复杂开关中的硬编码规则(如果业务需求发生变化,必须维护)将 Informants 连接到 Handlers,而是基于我们创建的多对多连接表这样做。任何用户现在都可以轻松更改他们认为合适的规则。
  • 然后我们添加一个排名函数,让我们知道我们可用的主要和后备处理程序选项。我们可以简单地选择每个 Informant 可用的排名最高的选项,这样我们就不会不必要地显示不必要的后备选项。
  • 一旦我们建立了这组数据,我们就可以从中选择以显示我们所有的 Informant 以及可用的处理程序。
  • 现在很容易通过获取(使用联合)不在 CTE 中的任何 Informant 来获取没有可用 Handler 的剩余 Informant。

可能还有其他方法可以做到这一点,但这就是我这次的思考过程。

于 2012-10-03T21:30:40.680 回答
0

首先,我建议您添加一个表来保留规则,如

 InformantRules
Type         PrimRatType SecRatType
Politicians   CIA           CIA 
Mobsters      FBI 
Famous        FBI 
Citizens      Police 
Foreign       NSA           CIA

然后你可以写

Select i.Name, i.Type, 
   Coalesce (p.Name, s.Name) ContactName
From Informants i
   Join InformantRules r On r.Type = i.Type
   Left Join Handlers p on p.HandlerId 
         = (Select Min(HandlerId) 
            From Handlers 
            Where HandlerType = r.PrimRatType)
   Left Join Handlers s on s.HandlerId 
         = (Select Min(HandlerId) 
            From Handlers 
            Where HandlerType = r.SecRatType)
于 2012-10-03T20:33:56.463 回答
0

你可以稍微改变你的加入条件:

SELECT 
   Informants.Name AS RatName,
   Informants.Type AS RatType,
   Handlers.Name AS GmanName,
   Handlers.HandlerID 
FROM Informants
   LEFT JOIN Handlers
   ON 
    (
      (Informants.Type IN ('Politician') AND (Handlers.HandlerType = CASE WHEN EXISTS (SELECT TOP 1 1 FROM Handlers WHERE HandlerType = 'CIA') THEN 'CIA' ELSE 'FBI' END))
      OR  
      (Informants.Type IN ('MOB', 'Famous') AND Handlers.HandlerType = 'FBI')
      OR
      (Informants.Type IN ('Citizen') AND Handlers.HandlerType = 'Police')
      OR
      (Informants.Type IN ('Foreign') AND (Handlers.HandlerType = CASE WHEN EXISTS (SELECT TOP 1 1 FROM Handlers WHERE HandlerType = 'NSA') THEN 'NSA' ELSE 'FBI' END))
    )
于 2012-10-03T20:51:50.353 回答