sql-server - 如何连接到一张表并回退到另一张表?

标签 sql-server sql-server-2008-r2

我想将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    |      +----------------------------------------+
+------------------------+

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

  • 政治家 --> 中央情报局
  • 黑帮和名人 --> 联邦调查局
  • 普通公民 --> 本地警察局
  • 外国特工 --> 可以向国家安全局求助

因此,我将举报者与他们可以通知的人进行匹配:

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两个个配置好的处理程序可以求助。同时:

  • 夫人。克拉维茨和
  • 白色棋子

没有可以通知的处理程序。

所以我现在想要的是处理程序的后备列表。如果您是政客外国特工,我们希望您求助于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

这是我的问题,我需要加入 an earlier join didn't match anything. 的标准


问题

我试图避免的问题是:

  • 主要案件将政客加入FBI
  • 备用案例将政治家加入到CIA

我最终得到的结果是这样的:

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

罗纳德·里根得到了一个新的“后备”条目,当时他已经有人要向其汇报了。

最佳答案

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

  • 使用标准化架构
  • 使用类型查找表并引用它们
  • 使用多对多联结表作为后备规则
  • 允许多种后备选项
  • 避免将逻辑放入代码中 - 在数据中进行

这是架构设置脚本:

-- 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。我们只是在 CTE 内做这件事。因为我们希望轻松地多次使用它(CTE 实际上是一个临时 View ,派生表、表变量或临时表也可以轻松工作)。
  • 我们不是基于复杂开关中的硬编码规则(如果业务需求发生变化就必须维护)将信息者连接到处理程序,而是基于我们创建的多对多联结表。任何用户现在都可以轻松更改他们认为合适的规则。
  • 然后,我们添加一个排名函数,让我们知道可用的主要和后备处理程序选项。我们可以简单地为每个举报人选择排名最高的选项,这样我们就不会不必要地显示不必要的后备选项。
  • 一旦建立了这组数据,我们就可以从中进行选择,以显示所有具有可用处理程序的举报人。
  • 现在可以通过获取(使用联合)任何不在 CTE 中的 Informant 来轻松获取没有可用处理程序的剩余 Informant。

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

关于sql-server - 如何连接到一张表并回退到另一张表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12716378/

相关文章:

sql-server - 在 SQL Server 中创建未记录的表

sql-server - 使用左连接后如何使用 case 语句?

sql - 需要大于 1 比 1 的结果

sql - 为什么当 xact_abort 打开时,Sql Server 在 raiserror 之后继续执行?

sql-server-2008 - 在 Crystal 报告的新窗口中打开链接

sql - 在创建 IDENTITY 的同一个 T-SQL 语句中获取 IDENTITY 值?

sql - Vb6 缺少运算符

sql - 使用分隔符连接多个字段

sql-server - 在 SQL Server 中通过递归 CTE 创建排列?

sql-server - 将非集群PK重建为集群PK?