1

请参考这个 SQLFiddle:http ://sqlfiddle.com/#!2/9db4f

表“费率”存储工作角色的每小时收费率,并可选择存储基于客户公司、组(“组”只是公司的一个部门)和客户联系人的角色的不同费率。

费率也可能随时间而变化。

我想为角色、公司、组和联系人的给定组合选择一个最近的、最合适的费率。它应该尝试按以下顺序匹配:

  1. client_contact、client_group、client_company 和角色
  2. 客户组、客户公司和角色
  3. 客户公司和角色
  4. 只是角色

例如:我正在寻找一个费率匹配角色 ID 3、公司 ID 3 和客户 ID 4。

没有与所有这些匹配的记录,因此它应该查找仅匹配角色 ID 3 和公司 ID 3 的记录。(其他字段 - client_contact 和 client_group - 必须为 NULL)。其中有两个:行 ID 的 2 和 3。它应该选择行 ID 3,因为它具有最近的“date_from”日期。

另一个例子:我正在寻找一个费率匹配的角色 ID 3 和公司 ID 25。其中也没有一个,因此它应该寻找一个仅匹配角色 ID 3 的角色,而所有其他值都为 NULL。只有一个匹配的行:数字 1。

当前 SQLFiddle 上的查询执行“获取最新”位,但我坚持让它匹配可选列(如果它们存在)。

哈尔普:(

编辑:哎呀,看起来 SQLFiddle 只保存模式,而不是查询。这就是我所拥有的:

SELECT 
  rate.*
FROM
  rate
LEFT JOIN rate AS newest ON (
  rate.role = newest.role
  AND COALESCE(rate.client_company, 1) = COALESCE(newest.client_company, 1)
  AND COALESCE(rate.client_group, 1) = COALESCE(newest.client_group, 1)
  AND COALESCE(rate.client_contact, 1) = COALESCE(newest.client_contact, 1)
  AND newest.date_from > rate.date_from
)
WHERE newest.id IS NULL
4

3 回答 3

2

我会这样处理它。

假设您正在寻找:

client_contact = 5
client_group= 3
client_company= 3
role = 3  

询问:

select *
from rate
where ifnull(client_contact, 5) = 5
    and ifnull(client_group, 3) = 3 
    and ifnull(client_company, 3) = 3 
    and ifnull(role, 3) = 3
order by case
    when client_contact = 5 and client_group = 3 and client_company = 3 and role = 3
      then 1
    when client_contact is null and client_group = 3 and client_company = 3 and role = 3
      then 2
    when client_contact is null and client_group is null and client_company = 3 and role = 3
      then 3
    when client_contact is null and client_group is null and client_company is null and role = 3
      then 4
end, date_from desc
limit 1

SQL 小提琴示例

于 2012-10-03T15:13:59.653 回答
0

在您返回的集合上,我会尝试根据可选列分配排名,因此排名越高,最接近匹配项,然后将获得具有 Max rank 的记录......(在SQL Fiddle上测试)

扩展您的查询:

SELECT T.*
FROM
(
    SELECT
      rate.*,
      ((CASE WHEN COALESCE(rate.client_company, 1) = COALESCE(newest.client_company, 1)
                       AND rate.client_company = 25  THEN 1
             ELSE 0 END) +
       (CASE WHEN COALESCE(rate.client_group, 1) = COALESCE(newest.client_group, 1)
                      AND rate.client_group = NULL THEN 1
             ELSE 0 END) +
       (CASE WHEN COALESCE(rate.client_contact, 1) = COALESCE(newest.client_contact, 1)
                      AND rate.client_contact = NULL THEN 1
             ELSE 0 END)) AS RANK
      FROM
        rate
      LEFT JOIN rate AS newest
        ON rate.role = newest.role
       AND COALESCE(rate.client_company, 1) = COALESCE(newest.client_company, 1)
       AND COALESCE(rate.client_group, 1) = COALESCE(newest.client_group, 1)
       AND COALESCE(rate.client_contact, 1) = COALESCE(newest.client_contact, 1)
       AND newest.date_from > rate.date_from
     WHERE newest.id IS NULL
       AND rate.role = 3
) T
HAVING T.Rank = MAX(T.Rank)

请注意:在我们有 rate.client_company = 25 的代码中,25 应替换为公司代码的输入参数。在我们有 rate.client_group = NULL 的代码中,NULL 应该替换为 Client Group Id 的输入参数在我们有 rate.client_contact = NULL 的代码中,NULL 应该替换为 ClientContactId 的输入参数在我们有 rate.role 的代码中= 3, 3 应替换为 RoleId 的输入参数。

我试图在 SQl Fiddle 中声明变量但无法这样做,所以我对上述值进行了硬编码......

于 2012-10-03T15:51:37.550 回答
0

我认为这意味着对于每个汇率记录,您都需要匹配的最新汇率。以下适用于给定的数据,但真正的答案是在此之后。

select rate.*,
       rmax.hourly_rate,
       rmax.maxdate
from rate join
     (select rmax.*, forhr.hourly_rate
      from (select role, client_company, client_group, client_contact, MAX(date_from) as maxdate
            from rate
            group by role, client_contact, client_group, client_company, role with rollup
           ) rmax join
           rate forhr
           on coalesce(rmax.role, '') = coalesce(forhr.role, '') and
              coalesce(rmax.client_company , '') = coalesce(forhr.client_company, '') and
              coalesce(rmax.client_contact, '') = coalesce(forhr.client_contact, '') and
              coalesce(rmax.client_group, '') = coalesce(forhr.client_group, '') and
              rmax.maxdate = forhr.date_from
     ) rmax
     on coalesce(rmax.role, '') = coalesce(rate.role, '') and
        coalesce(rmax.client_company , '') = coalesce(rate.client_company, '') and
        coalesce(rmax.client_contact, '') = coalesce(rate.client_contact, '') and
        coalesce(rmax.client_group, '') = coalesce(rate.client_group, '')

内部查询只是为了获取与日期相关的最新汇率。外部查询对费率表中的每条记录进行匹配。

我不确定我在想什么;我想我的思维过程被打断了。我认为解决此问题的最佳方法是使用相关子查询。以下获得最大速率。您可以使用相同的方法来获取 id 和其他信息:

select r.*,
       (select hourly_rate
        from rates r2
        where coalesce(r.role, '') = coalesce(r2.role, '') and
              coalesce(r.client_company , '') = coalesce(r2.client_company, '') and
              coalesce(r.client_contact, '') = coalesce(r2.client_contact, '') and
              coalesce(r.client_group, '') = coalesce(r2.client_group, '')
        order by (case when r2.client_contact is not null then 1
                       when r2.client_group is not null then 2
                       when r2.client_company is not null then 3
                       when r2.role is not null then 4
                       else 5
                  end),
                 date_from desc
        limit 1
       ) as most_recent_hourly_rate
from rates r

这使用相关子查询来获取匹配最多的行。关键是order by子句,它按“最匹配”字段到“最不匹配”字段排序,然后按日期排序。在这种情况下,它会拉动小时费率。在实践中,我会拉出 id 并加入到费率中以获取费率和其他信息(例如日期)。

在给定的表单中,它假定数据rates按照您所说的那样结构化,并且您没有包含 client_group 和 role 的行,但没有其他字段。

于 2012-10-03T15:20:38.170 回答