如何向SQL的“质量检查”规则添加异常?

huangapple go评论59阅读模式
英文:

How to Add an Exception to a SQL 'Quality Check' Rule?

问题

我有以下查询:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON  
            A.ID = B.ID
LEFT JOIN REFERENCE_TABLE C ON
A.FUND = C.FUND
WHERE 
B.MANAGER_NAME != C.MGR_NM

此查询的结果显示了当将经理错误地分配给基金时的情况。

REFERENCE_TABLE 是真相来源,显示了正确的 FUNDMGR_NM 分配。然而,我需要为这一规则添加一个例外情况:当 FUND = 'BOSTON' 时,如果 MANAGER_NAME = 'Kim, John, or Danny',那是可以的。

所有其他基金都有基金和经理姓名之间的一对一关系。

如何将这个例外情况添加到我的查询中?

英文:

I have the following query:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON  
            A.ID = B.ID
LEFT JOIN REFERENCE_TABLE C ON
A.FUND = C.FUND
WHERE 
B.MANAGER_NAME != C.MGR_NM

The results of this query show when a Manager is incorrectly assigned to a fund.

The REFERENCE_TABLE is the source of truth and shows the correct FUND and MGR_NM assignments. However, I need to add one exception to this rule: when FUND = 'BOSTON', it's okay if MANAGER_NAME = 'Kim, John, or Danny'.

All other funds have a 1:1 relationship between fund and manager name.
How can I add this exception to my query?

答案1

得分: 3

> 显示所有结果,其中MANAGER_NAMEMGR_NM不匹配,除非FUND是'BOSTON',那么如果MANAGER_NAME是'Kim, John, or Danny'之一,也是可以的。

这似乎需要在您的条件中使用一个简单的OR表达式,但我们需要反转对'Kim, John, or Danny'的匹配,并在基金是'BOSTON'且MANAGER_NAME不是'Kim, John, or Danny'之一时返回。

但这并不是太简单,当将OR运算符插入您的条件时要小心,如果您没有使用括号来分隔条件中的逻辑表达式,那么OR将独立比较运算符两侧,这可能会产生不希望的结果。

在以下解决方案中未使用括号,但我们必须对原始逻辑中的'BOSTON'基金进行非匹配评估,以便'Kim'、'John'、'Danny'不被视为其他基金的有效值:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON A.ID = B.ID
LEFT JOIN REFERENCE_TABLE C ON A.FUND = C.FUND
WHERE 
A.FUND <> 'BOSTON' 
AND B.MANAGER_NAME != C.MGR_NM
OR A.FUND = 'BOSTON' 
   AND B.MANAGER_NAME != C.MGR_NM 
   AND B.MANAGER_NAME NOT IN ('Kim', 'John', 'Danny')

您可能更喜欢使用括号使表达更易阅读,或者突出特殊情况。RDBMS可能会在评估时扩展括号,因此无论哪种方式都不会对性能产生影响,但如果有帮助的话,它确实允许我们使用这样的语法:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON A.ID = B.ID
LEFT JOIN REFERENCE_TABLE C ON A.FUND = C.FUND
WHERE 
B.MANAGER_NAME != C.MGR_NM
AND (
    A.FUND <> 'BOSTON' 
    OR A.FUND = 'BOSTON' 
       AND B.MANAGER_NAME NOT IN ('Kim', 'John', 'Danny')
    )

虽然这应该可以工作,但问题是_为什么'Kim'、'John'、'Danny'是有效的?_ 如果REFERENCE_TABLE是真相的来源,那么您可以允许在这个表中为每个基金允许多个条目,然后根本不需要硬编码'BOSTON'的特定情况,我们可以使用OUTER JOIN来仅返回非关联的行:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON A.ID = B.ID
LEFT OUTER JOIN REFERENCE_TABLE C ON A.FUND = C.FUND 
                                  AND B.MANAGER_NAME = C.MGR_NM
WHERE 
C.FUND IS NULL

这是因为所有有效的管理者将匹配并且对于C.FUND将具有非空值。然而,在REFERENCE_TABLE中找不到相应匹配的所有行将具有null值的C.FUND,这些是我们想要查看的行。

英文:

> Show all results where MANAGER_NAME does not match MGR_NM, unless the FUND is 'BOSTON', then it is okay if MANAGER_NAME is one of 'Kim, John, or Danny'

Sounds like a case for a simple OR expression in your criteria, but we need to invert the match on 'Kim, John, or Danny' and return if the fund is 'BOSTON' and the MANAGER_NAME is NOT one of 'Kim, John, or Danny'

But it's not too simple, be careful when injecting OR operator into your criteria though, if you are not using brackets to separate the logical expressions in the criteria then OR will compare either side of the operator independently which can produce undesirable results.

In the following solution no brackets are used, but we have to evaluate a non-match for the BOSTON fund in the original logic so that 'Kim', 'John', 'Danny' are not considered valid for other funds:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON A.ID = B.ID
LEFT JOIN REFERENCE_TABLE C ON A.FUND = C.FUND
WHERE 
A.FUND &lt;&gt; &#39;BOSTON&#39; 
AND B.MANAGER_NAME != C.MGR_NM
OR A.FUND = &#39;BOSTON&#39; 
   AND B.MANAGER_NAME != C.MGR_NM 
   AND B.MANAGER_NAME NOT IN (&#39;Kim&#39;, &#39;John&#39;, &#39;Danny&#39;)

You might prefer to use brackets to make the expression more readable, or to highlight the exceptional case. The RDBMS is likely to expand the brackets on evaluation anyway so it shouldn't have an impact on performance either way, but it does allow us to use syntax like this if it is helpful:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON A.ID = B.ID
LEFT JOIN REFERENCE_TABLE C ON A.FUND = C.FUND
WHERE 
B.MANAGER_NAME != C.MGR_NM
AND (
    A.FUND &lt;&gt; &#39;BOSTON&#39; 
    OR A.FUND = &#39;BOSTON&#39; 
       AND B.MANAGER_NAME NOT IN (&#39;Kim&#39;, &#39;John&#39;, &#39;Danny&#39;)
    )

While this should work, the question is why are 'Kim', 'John', 'Danny' valid? If REFERENCE_TABLE is the source of truth then you could allow multiple entries for each fund in this table, then you wouldn't need to hardcode the specific case for 'BOSTON' at all and we can use an OUTER JOIN to return only the non-correlated rows:

SELECT A.ID, A.FUND, B.MANAGER_NAME, C.FUND, C.MGR_NM
FROM TABLE_1 A 
LEFT JOIN TABLE_2 B ON A.ID = B.ID
LEFT OUTER JOIN REFERENCE_TABLE C ON A.FUND = C.FUND 
                                  AND B.MANAGER_NAME = C.MGR_NM
WHERE 
C.FUND IS NULL

This works because all the valid manager will match and will have a non-null value for C.FUND. However all rows that do not find a corresponding match in the REFERENCE_TABLE will have a value of null for C.FUND, these are the rows that we want to see.

huangapple
  • 本文由 发表于 2023年4月10日 22:13:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定