我有两张表很容易加入,第三张表给我带来了麻烦。首先,表格:
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
也没有任何帮助,因为“女士”和“女王”在{{1}中的日期都是活跃的}。
此时,除了tbl_customer
中的“排名”之外别无选择。 “女王”比“女士”高出20到10,所以我想在tbl_group
中使用该标题。如果排名相等,我想只使用tbl_customer
中的第一条记录。 (这可以通过某种内部排序来解决吗?)
棘手的部分是在排名之前需要考虑活动/非活动动态。例如,我不想先为每个组的一个标题过滤tbl_group
,因为这会阻止基于日期的匹配。
理想情况下,我需要从显示标题的tbl_group
每个条目返回一行,首先根据活动/非活动日期。接下来,我想使用tbl_customer
消除重复项。最后,我想使用tbl_group
中的匹配和排名将结果限制为tbl_customer
中每个条目的一行。这甚至可能吗?
答案 0 :(得分: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]
声明。为什么所有四列?原因是我不知道唯一标识客户行的是什么。如果该表上有主键,我们可以简单地进行分区。
答案 1 :(得分: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的最大排名。然后我们过滤行只返回排名是客户最大排名的行。
答案 2 :(得分: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