3

我有两张很容易加入的桌子,第三张给我带来了麻烦。首先,表格:

tbl_customer
id  dt           value  group
a   2013-01-01   10     cavalry
a   2012-06-01   20     lance
a   2011-03-01   10     infantry
b   2013-01-01   20     court
b   2012-07-01   5      maiden
b   2005-06-01   10     chivalry

tbl_title
id  dt_active    dt_inactive   title
a   2001-01-01   2012-01-01    mister
a   2012-01-02   3001-01-01    sir
a   2012-01-02   3001-01-01    king
b   2001-01-01   2012-01-01    miss
b   2012-01-02   3001-01-01    lady
b   2012-01-02   3001-01-01    queen

使用以下方法很容易加入以返回给定 ID 的标题:

SELECT 
  id, dt, value, title
FROM
  tbl_customer AS cust
INNER JOIN tbl_title AS titles
  ON titles.id = cust.id
  AND dt >= titles.dt_active
  AND dt <= titles.dt_inactive

这将返回tbl_customer包含多个“活动”标题的重复行中的所有行。例如,第一行tbl_customer返回两次,一次是“king”,一次是“sir” title

我有第三个表将组链接到标题。它可以帮助解决这些关系:

tbl_group
group     title   rank
cavalry   sir     10
lance     king    20
infantry  mister  30
court     lady    10
court     queen   20
maiden    lady    10
chivalry  miss    5

然后我可以加入表格以包含标题tbl_group并将结果限制为匹配的结果:

SELECT 
  id, dt, value, titles.title
FROM
  tbl_customer AS cust
INNER JOIN tbl_title AS titles
  ON titles.id = cust.id
  AND dt >= titles.dt_active
  AND dt <= titles.dt_inactive
INNER JOIN tbl_group AS group
  ON group.group = cust.group
WHERE
  titles.title = group.title

这在很大程度上解决了我的问题。第三个表有助于消除 . 中存在多个“活动”记录时的歧义tbl_title

但是,有一个问题。第三个表也可以有多个与组关联的标题。因此,最终输出中仍然可能存在重复。在上面的示例中,“骑兵”明确地与“先生”头衔相关联。但是,组“法院”可以是“女士”或“女王”,tbl_title也没有任何帮助,因为“女士”和“女王”都在tbl_customer.

在这一点上,我除了“排名”之外别无选择tbl_group。“女王”的排名比“女士”高 20 到 10,所以我想在tbl_customer. 如果排名相等,我只想使用tbl_group. (这可以通过某种内部排序来解决吗?

棘手的部分是在排名之前需要考虑活动/非活动动态。例如,我不想首先过滤tbl_group每个组的一个标题,因为这会阻止基于日期的可能匹配。

理想情况下,我需要从显示标题的每个条目返回一行tbl_customer,首先基于活动/非活动日期。接下来,我想使用tbl_group. tbl_customer最后,我想在使用 match 和 rank from时将结果限制为每个条目仅一行tbl_group。这甚至可能吗?

4

3 回答 3

2

首先,一些实际的表模式会有所帮助,因为您提供的表数据缺少一些关键元素。每个表中的键是什么?即,什么可以用来唯一标识每个表中的一行?id客户和标题表中的列代表什么?当然不是客户标识符,因为有重复。

其次,要回答您的问题,您可以使用排名函数,例如Row_Number对列表中的项目进行排名,并且只返回给定集合的第一项:

With RnkItems As
  (
  Select C.id, C.dt, C.value, T.Title
    , Row_Number() Over ( Partition By C.id, C.dt, C.value, C.[group]
                          Order By G.rank Desc ) As Rnk
  From tbl_customer As C
    Join tbl_title As T
      On T.id = C.id
        And C.dt Between T.dt_active And T.dt_inactive
    Join tbl_group As G
      On G.[group] = C.[group]
        And G.title = T.title
  )
Select id, dt, value, title
From RnkItems
Where Rnk = 1

关键是Partition By C.id, C.dt, C.value, C.[group]陈述。为什么所有四列?原因是我不知道是什么唯一标识了一个客户行。如果该表上有一个主键,我们可以简单地按它进行分区。

SQL 小提琴版本

于 2013-09-18T15:18:03.927 回答
1

尝试这个:

SELECT *
FROM
(
SELECT 
  id, 
  dt, 
  value, 
  titles.title, 
  group.rank MAX(rank) OVER(PARTITION BY cust.id) AS MAX_RANK
FROM
  tbl_customer AS cust
INNER JOIN tbl_title AS titles
  ON titles.id = cust.id
  AND dt BETWEEN titles.dt_active AND titles.dt_inactive
INNER JOIN tbl_group AS group
  ON group.group = cust.group
WHERE
  titles.title = group.title
) AS RESULTS
WHERE rank = MAX_RANK

窗口函数MAX(rank) OVER(PARTITION BY cust.id)将获得每个 id 的最大排名。然后我们过滤行以仅返回其排名是该客户的最大排名的行。

于 2013-09-18T15:05:33.763 回答
0
SELECT  *
FROM    (
        SELECT  *,
                ROW_NUMBER() OVER (PARTITION BY g.group, g.title ORDER BY g.rank DESC) rn
        FROM    tbl_customer с
        JOIN    tbl_title t
        ON      t.id = c.id
                AND c.dt BETWEEN t.dt_active AND t.dt_inactive
        JOIN    tbl_group g
        ON      g.[group] = c.[group]
                AND g.title = c.title
        ) q
WHERE   rn = 1
于 2013-09-18T15:06:05.560 回答