简体   繁体   English

检索SQL查询中的第一个真实条件

[英]Retrieve the First True Condition in a SQL Query

I'm running into a problem wherein I need to get the changes of an Employee based on specific conditions. 我遇到了一个问题,其中我需要根据特定条件获取Employee的更改。

I should retrieve rows only based on the changes below: 我应该仅根据以下更改检索行:

  1. Assignment Category (only based on specific Categories shown in the table xxtest) 分配类别(仅基于表xxtest中显示的特定类别)
  2. Pay Basis (only from Hourly to Salaried and Vice Versa, also shown in the table xxtest) 薪资基础(仅从每小时到薪水和反之亦然,也显示在表xxtest中)
  3. Both Pay Basis and Assignment Category (based on the same constraints above) 薪酬基础和工作分配类别(基于上述相同的约束)

I have created a Table (XXTEST) to restrict the SQL to only reference this mapping (See DML and DDL at the end of the Question). 我创建了一个表(XXTEST)来限制SQ​​L仅引用此映射(请参阅问题末尾的DML和DDL)。

Basically, the Data I'm Expecting would be: 基本上,我期望的数据是:

| --------|-------------------|------------------|---------------|------------- |-------------|
| Sample  | FROM_PAY_BASIS_ID | TO_PAY_BASIS_ID  | FROM_CATEGORY | TO_CATEGORY  | CHANGE_TYPE |
| --------| ------------------| -----------------| --------------|------------- |-------------|
| 1       | 1                 | 2                | FR            | FR           | PAY_BASIS   |
| 2       | 1                 | 1                | FT            | FR           | ASSIGN_CAT  |
| 3       | 1                 | 2                | FT            | FR           | BOTH        |

the table above is based on the conditions below: 上表基于以下条件:

1. if BOTH, it should get "Assignment Category and Pay Basis" as its Change_Type
2. if Assignment Category, it should get "Assignment Category" as its Change_Type
3. if Pay Basis, it should get "Pay Basis" as its Change_Type 

I want it to evaluate first the condition 1, and if its false, then evaluate the next until the last. 我希望它首先评估条件1,如果条件为假,则评估下一个条件直到最后一个条件。
the problem occurs when both of these columns change, resulting into having 3+ rows with CHANGE_TYPE having "PAY_BASIS", "ASSIGN_CAT", "BOTH" as values. 当这两个列都发生更改时,就会出现问题,导致具有3+行,其CHANGE_TYPE的值为“ PAY_BASIS”,“ ASSIGN_CAT”,“ BOTH”。

I've tried a lot of methods but nothing seemed to fully address my need, such as the query below: 我尝试了很多方法,但是似乎没有什么可以完全满足我的需求,例如以下查询:

select  *
from    (select coalesce((select  CHANGE_TYPE
                          from    XXTEST  
                          where   FROM_CATEGORY   = pax.EMPLOYMENT_CATEGORY    
                          AND     TO_CATEGORY     = pax2.EMPLOYMENT_CATEGORY
                          AND     FROM_ID         = pax.PAY_BASIS_ID
                          and     TO_ID           = pax2.PAY_BASIS_ID),
                          select  CHANGE_TYPE
                          from    XXTEST  
                          WHERE   FROM_CATEGORY   = pax.EMPLOYMENT_CATEGORY    
                          AND     TO_CATEGORY     = pax2.EMPLOYMENT_CATEGORY
                          AND     FROM_ID         = 0
                          and     TO_ID           = 0),
                          select  CHANGE_TYPE
                          from    XXTEST  
                          WHERE   FROM_CATEGORY   = 'N/A'
                          AND     TO_CATEGORY     = 'N/A'
                          AND     FROM_ID         = pax.PAY_BASIS_ID
                          and     TO_ID           = pax2.PAY_BASIS_ID),
                          NULL ) CHANGE_TYPE FROM DUAL ) CHANGE_TYPE
            ,   PPX.FULL_NAME
            ,   PPX.EMPLOYEE_NUMBER
        from    per_people_X          ppx
            ,   per_assignments_X     pax 
            ,   per_assignments_X     pax2
        WHERE   pax.assignment_id     = pax2.assignment_id
        AND     PPX.PERSON_id         = pax2.PERSON_id
        AND     PPX.PERSON_id         = PAX.PERSON_id)
where   CHANGE_TYPE is not null;

This kinda works but it retrieves all records, regardless if it has a match or not (due to the NULL "else" condition) and results into Change_Type = NULL. 这种方法可以工作,但是无论是否有匹配项(由于NULL“ else”条件),它都会检索所有记录,并导致Change_Type = NULL。 Is it possible to just filter only those records that do not have Change_Type = NULL without encasing it in another SELECT statement? 是否可以仅过滤那些没有Change_Type = NULL的记录而不将其封装在另一个SELECT语句中?

I've also tried using CASE, It works fine if the Employee's Pay Basis ID only changed (ex. from 1 to 2) and if only the Employee's Category has changed (ex. from FT to FR), but it evaluates all the cases (returning 3 rows) whenever "both" changes occur. 我也尝试过使用CASE,如果仅更改了雇员的工资基础ID(例如,从1更改为2),并且仅更改了雇员的类别(例如,从FT更改为FR),则它可以正常工作,但是它会评估所有情况(返回3行)无论何时发生“两个”更改。

Any advise? 有什么建议吗?

You are probably after case statements in the where clause, something like: 您可能在where子句中的case语句之后,例如:

SELECT  PPX.FULL_NAME
    ,   PPX.EMPLOYEE_NUMBER
    ,   XT.CHANGE_TYPE
FROM    per_people_X          ppx
    ,   XXTEST                XT
    ,   per_assignments_X     pax 
    ,   per_assignments_X     pax2
WHERE   pax.assignment_id     = pax2.assignment_id
AND     PPX.PERSON_id         = pax2.PERSON_id
AND     PPX.PERSON_id         = PAX.PERSON_id
AND     (-- Both Employment Category and Pay Basis records records that were Changed
         case when     XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
                   AND XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
                   AND XT.FROM_ID       = pax.PAY_BASIS_ID           
                   AND XT.TO_ID         = pax2.PAY_BASIS_ID
                   then 1
              else 0
         end = 1
         OR
         -- all Pay Basis records that were "Updated"
         case when     XT.FROM_CATEGORY = 'N/A'
                   AND XT.TO_CATEGORY   = 'N/A'
                   AND XT.FROM_ID       = pax.PAY_BASIS_ID           
                   AND XT.TO_ID         = pax2.PAY_BASIS_ID
                   then 1
              else 0
         end = 1
         OR
         -- all Assignment Category records that were "Updated"
         case when     XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
                   AND XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
                   AND XT.FROM_ID       = 0       
                   AND XT.TO_ID         = 0
                   then 1
              else 0
         end = 1);

NB untested, since you didn't provide sample data for the per_people_x or per_assignments tables. NB未经测试,因为您没有为per_people_x或per_assignments表提供样本数据。

You may have to add extra conditions into the "both categories" case expression to exclude the other two cases; 您可能需要在“两个类别”的情况表达式中添加其他条件,以排除其他两个情况; it's not immediately apparent from the data that you have supplied so far. 到目前为止,您提供的数据尚无法立即看出来。

First of all if you use OR you should use brackets and (... or ... ) or you lose some predicates. 首先,如果使用OR,则应使用方括号and (... or ... )否则会丢失某些谓词。 Your first query should be rewritten to: 您的第一个查询应重写为:

SELECT  PPX.FULL_NAME
,   PPX.EMPLOYEE_NUMBER
,   XT.CHANGE_TYPE
FROM    per_people_X          ppx
,   XXTEST                XT
,   per_assignments_X     pax 
,   per_assignments_X     pax2
WHERE   pax.assignment_id     = pax2.assignment_id
AND     PPX.PERSON_id         = pax2.PERSON_id
AND     PPX.PERSON_id         = PAX.PERSON_id
-- THIS IS THE SECTION OF THE QUERY WHERE I'M HAVING PROBLEMS -- 
-- Both Employment Category and Pay Basis records records that were Changed
AND ( 
     (XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
    AND      XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
    AND      XT.FROM_ID       = pax.PAY_BASIS_ID           
    AND      XT.TO_ID         = pax2.PAY_BASIS_ID)
    -- all Pay Basis records that were "Updated"
    or      (XT.FROM_CATEGORY = 'N/A'
    AND      XT.TO_CATEGORY   = 'N/A'
    AND      XT.FROM_ID       = pax.PAY_BASIS_ID           
    AND      XT.TO_ID         = pax2.PAY_BASIS_ID)
    -- all Assignment Category records that were "Updated"
    or      (XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
    AND      XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
    AND      XT.FROM_ID       = 0       
    AND      XT.TO_ID         = 0)
);

EDIT: Add solution with ranking of condition 编辑:添加条件等级的解决方案

SELECT FULL_NAME
,   EMPLOYEE_NUMBER
,   CHANGE_TYPE
FROM (
SELECT  PPX.FULL_NAME
,   PPX.EMPLOYEE_NUMBER
,   XT.CHANGE_TYPE
,   DENSE_RANK() OVER (PRTITION BY PPX.PERSON_id,pax.assignment_id ORDER BY
   CASE WHEN XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
             AND      XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
             AND      XT.FROM_ID       = pax.PAY_BASIS_ID           
             AND      XT.TO_ID         = pax2.PAY_BASIS_ID 
        THEN 1
        WHEN XT.FROM_CATEGORY = 'N/A'
             AND      XT.TO_CATEGORY   = 'N/A'
             AND      XT.FROM_ID       = pax.PAY_BASIS_ID           
             AND      XT.TO_ID         = pax2.PAY_BASIS_ID
        THEN 2
        ELSE 3 
    END
    ) as RNK
FROM    per_people_X          ppx
,   XXTEST                XT
,   per_assignments_X     pax 
,   per_assignments_X     pax2
WHERE   pax.assignment_id     = pax2.assignment_id
AND     PPX.PERSON_id         = pax2.PERSON_id
AND     PPX.PERSON_id         = PAX.PERSON_id
-- THIS IS THE SECTION OF THE QUERY WHERE I'M HAVING PROBLEMS -- 
-- Both Employment Category and Pay Basis records records that were Changed
AND ( 
     (XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
    AND      XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
    AND      XT.FROM_ID       = pax.PAY_BASIS_ID           
    AND      XT.TO_ID         = pax2.PAY_BASIS_ID)
    -- all Pay Basis records that were "Updated"
    or      (XT.FROM_CATEGORY = 'N/A'
    AND      XT.TO_CATEGORY   = 'N/A'
    AND      XT.FROM_ID       = pax.PAY_BASIS_ID           
    AND      XT.TO_ID         = pax2.PAY_BASIS_ID)
    -- all Assignment Category records that were "Updated"
    or      (XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY    
    AND      XT.TO_CATEGORY   = pax2.EMPLOYMENT_CATEGORY
    AND      XT.FROM_ID       = 0       
    AND      XT.TO_ID         = 0)
)
) WHERE RNK = 1;

I didn't follow all the details of your post and the answers and ensuing comments, but it seems you may be after something like this. 我没有关注您的帖子的所有详细信息,答案和随后的评论,但看来您可能正在追求这样的想法。 To get exactly one answer in all situations, you probably need a CASE expression. 为了在所有情况下都能得到一个准确的答案,您可能需要一个CASE表达式。 In the code below I use nested CASE expressions, but that is only to save typing (and a little bit of execution time); 在下面的代码中,我使用嵌套的CASE表达式,但这只是为了节省键入时间(以及执行时间)。 you could rewrite this using a single CASE expression. 可以使用单个CASE表达式重写它。

The reason this works is that evaluation ends immediately as soon as the first TRUE condition in the when... then... pairs is found. 之所以起作用,是因为一旦在when... then...对中找到第一个TRUE条件,评估就会立即结束。 You will have to figure out how to attach this to your existing query - I just put its outputs in a CTE for testing purposes below. 您将必须弄清楚如何将其附加到您现有的查询中-我仅将其输出放在CTE中,以进行下面的测试。

with
     query_output ( empl_id, from_pay_basis_id, to_pay_basis_id, from_category, to_category ) as (
       select 101, 1, 2, 'FR', 'FR' from dual union all
       select 102, 1, 1, 'FT', 'FR' from dual union all
       select 103, 1, 2, 'FT', 'FR' from dual union all
       select 104, 1, 1, 'FR', 'FR' from dual
     )
select empl_id, from_pay_basis_id, to_pay_basis_id, from_category, to_category,
       case when from_category != to_category then
                 case when from_pay_basis_id != to_pay_basis_id then 'Assignment Category and Pay Basis'
                      else                                     'Assignment Category'
                 end
            when from_pay_basis_id != to_pay_basis_id then 'Pay Basis'
       end as change_type
from   query_output;

EMPL_ID FROM_PAY_BASIS_ID   TO_PAY_BASIS_ID FROM_CATEGORY   TO_CATEGORY CHANGE_TYPE
------- ----------------- --------------- ------------- ----------- ---------------------------------
101                     1               2 FR            FR          Pay Basis
102                     1               1 FT            FR          Assignment Category
103                     1               2 FT            FR          Assignment Category and Pay Basis
104                     1               1 FR            FR

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 CASE WHEN SQL 查询在 else 中执行条件,即使第一个条件为真 - CASE WHEN SQL Query executes condition in else even if first condition is true 如果第一个条件为true,则停止从SQL查询的where子句中的其他条件获取数据 - If first condition is true then stop fetching from the other conditions in where clause of a SQL query SQL查询:检索具有不同条件的列 - SQL Query: Retrieve columns with different condition SQL 查询:如何仅在条件为真时检查 ON 子句中的 Join 条件 - SQL Query: How to check for the Join condition in ON clause only if a condition is true SQL 查询以检索某个名字 - SQL Query to retrieve a certain first name 如果第一个为true,如何在MySQL查询中使用OR并忽略第二个条件? - How to use OR in MySQL query and ignore second condition if first is true? SQL查询在条件的第一次匹配时中断 - SQL query to break at first match of the condition SQL 日期查询 - 此条件成立多长时间 - SQL Dates Query - how long has this condition been true Oracle SQL查询使用xpath中的特定条件来检索特定事件? - Oracle SQL Query to retrieve specific Event using specific condition in xpath? 嵌套集 SQL 查询以检索每个节点的第一个祖先 - Nested Set SQL Query to retrieve the first ancestor of each node
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM