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

时间:2016-10-19 09:21:05

标签: sql oracle oracle11g

我遇到了一个问题,我需要根据具体情况对员工进行更改。

我应该仅根据以下更改检索行:

  1. 作业类别(仅基于表xxtest中显示的特定类别)
  2. 支付基础(仅从小时到工资和反之亦然,也在表xxtest中显示)
  3. 支付基础和分配类别(基于上述相同的限制)
  4. 我创建了一个表(XXTEST)来限制SQ​​L仅引用此映射(请参阅问题末尾的DML和DDL)。

    基本上,我期待的数据将是:

    | --------|-------------------|------------------|---------------|------------- |-------------|
    | 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        |
    

    上表基于以下条件:

    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 
    

    我希望它首先评估条件1,如果它是假的,那么评估下一个直到最后一个 当这两列都发生变化时会出现问题,导致有3行以上的CHANGE_TYPE具有" PAY_BASIS"," ASSIGN_CAT"," BOTH"作为价值观。

    我尝试了很多方法,但似乎没有任何方法可以完全满足我的需求,例如下面的查询:

    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;
    

    这种方法有效,但它检索所有记录,无论它是否匹配(由于NULL" else"条件),结果为Change_Type = NULL。 是否可以仅过滤那些没有Change_Type = NULL的记录而不将其包含在另一个SELECT语句中?

    我也尝试过使用CASE, 如果仅更改员工的薪资基础ID(例如从1到2),它可以正常工作 如果只有员工的类别发生了变化(例如从FT到FR), 但它会评估所有情况(返回3行),每当"两者都是"发生了变化。

    有任何建议吗?

3 个答案:

答案 0 :(得分:0)

您可能在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);

N.B。未经测试,因为您没有为per_people_x或per_assignments表提供示例数据。

您可能需要在“两个类别”案例表达式中添加额外条件以排除其他两种情况;从目前为止提供的数据来看,并不是很明显。

答案 1 :(得分:0)

首先,如果使用OR,则应使用括号and (... or ... ),否则会丢失一些谓词。您的第一个查询应该重写为:

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)
);

编辑:添加条件排名

的解决方案
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;

答案 2 :(得分:0)

我没有按照你的帖子的所有细节,答案和随后的评论,但似乎你可能会在这样的事情之后。要在所有情况下得到一个答案,您可能需要一个CASE表达式。在下面的代码中,我使用嵌套的CASE表达式,但这只是为了节省输入(以及一点执行时间); 可以使用单个CASE表达式重写此内容。

这样做的原因是,只要找到when... then...对中的第一个TRUE条件,评估就会立即结束。您将不得不弄清楚如何将其附加到现有查询 - 我只是将其输出放在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