【问题标题】:SQL WITH Clause and OR operatorSQL WITH 子句和 OR 运算符
【发布时间】:2021-10-25 15:16:37
【问题描述】:

我正在尝试根据下面给出的某些条件获取一些记录 -

WITH temp_data AS(SELECT t1.acc_name,t1.f_data,t1.EXPIRY_DATE,t1.f_days
            FROM t1_table t1, t2_table t2 where 
            t1.acc_name = t2.acc_name
            AND t2.FLAG = 2)            
SELECT tmp_data.acc_name 
FROM    temp_data tmp_data ,t3_table t3  where
( tmp_data.f_data = 'N' AND tmp_data.EXPIRY_DATE <= SYSDATE)
OR 
( tmp_data.f_data = 'Y' AND tmp_data.acc_name =  t3.acc_name 
              AND
              (
                (t3.f_interval_period <>-1 AND t3.f_DATE <= SYSDATE)
              OR (t3.f_interval_period =-1 AND  t3.f_DATE+t1.f_days <= SYSDATE)
              ))

当 tmp_data.f_data = 'N' AND tmp_data.EXPIRY_DATE

  WITH temp_data AS(SELECT t1.acc_name,t1.f_data,t1.EXPIRY_DATE,t1.f_days
                    FROM t1_table t1, t2_table t2 where 
                    t1.acc_name = t2.acc_name
                    AND t2.FLAG = 2)            
        SELECT tmp_data.acc_name 
        FROM    temp_data tmp_data  where
        ( tmp_data.f_data = 'N' AND tmp_data.EXPIRY_DATE <= SYSDATE)

==> 这没有添加 t3_table 并且只提供 1 个帐户名并且工作正常, 但是将这两个 (tmp_data.f_data = 'N' , 'Y') 与 OR 合并,我没有得到预期的结果,并且相同的 account_number 会重复多次。

【问题讨论】:

    标签: sql oracle common-table-expression or-operator


    【解决方案1】:

    我想您缺少连接条件,我猜是 tmp_data.acc_name = t3.acc_name 用于“N”条件。因此,当您组合结果时,您可能会得到 tmp_data 和 t3 数据集的笛卡尔积,这会影响您的结果。 只是猜测,您必须以某种方式进行更改:

    ....
    FROM   temp_data tmp_data, t3_table t3
    where
       tmp_data.acc_name =  t3.acc_name and
       (
          ( tmp_data.f_data = 'N' AND tmp_data.EXPIRY_DATE <= SYSDATE)
          OR 
          (
            tmp_data.f_data = 'Y'
            AND
            (
               (t3.f_interval_period <> -1 AND  t3.f_DATE <= SYSDATE)
               OR
               (t3.f_interval_period =  -1 AND  t3.f_DATE + t1.f_days <= SYSDATE)
            )
          )
       )
    

    更新 1:考虑左外连接,如果我没记错的话,在 Oracle 中使用了 (+)

    ....
    FROM   temp_data tmp_data, t3_table t3
    where
       tmp_data.acc_name =  t3.acc_name (+) and
       (
          ( tmp_data.f_data = 'N' AND tmp_data.EXPIRY_DATE <= SYSDATE)
          OR 
          (
            tmp_data.f_data = 'Y' and t3.acc_name is not null
            AND
            (
               (t3.f_interval_period <> -1 AND  t3.f_DATE <= SYSDATE)
               OR
               (t3.f_interval_period =  -1 AND  t3.f_DATE + t1.f_days <= SYSDATE)
            )
          )
       )
    

    注意你需要acc_name的地方,指定条件t3.acc_name is not null

    更新 2:如果您的 Oracle 版本支持 join 关键字,很可能它支持

    WITH temp_data AS(SELECT t1.acc_name,t1.f_data,t1.EXPIRY_DATE,t1.f_days
                FROM t1_table t1 inner join t2_table t2 on t1.acc_name = t2.acc_name
                where  t2.FLAG = 2)            
    SELECT tmp_data.acc_name 
    FROM    temp_data tmp_data left join t3_table t3  on tmp_data.acc_name =  t3.acc_name 
    where
    ( tmp_data.f_data = 'N' AND tmp_data.EXPIRY_DATE <= SYSDATE)
    OR 
    ( tmp_data.f_data = 'Y' AND t3.acc_name is not null
                  AND
                  (
                    (t3.f_interval_period <>-1 AND t3.f_DATE <= SYSDATE)
                  OR (t3.f_interval_period =-1 AND  t3.f_DATE+t1.f_days <= SYSDATE)
                  ))
    

    【讨论】:

    • 是的,这正是问题所在,但我只需要'Y'而不是'N'中的t3_table条件
    • 您需要正确指定连接条件,否则对于一个表中的每条记录,您将获得另一个表中的完整记录集。那是笛卡尔积。否则,您将不得不进行两个单独的查询并通过unionunion all 组合它们
    • Union 所有我试过的,它的重复 - SELECT t1.acc_name,t1.f_data,t1.EXPIRY_DATE,t1.f_days FROM t1_table t1, t2_table t2 where t1.acc_name = t2.acc_name AND t2 .FLAG = 2, 两次,所以需要用 WITH 子句写
    • 所以,我在想,你需要一个查询,它在某种情况下跟随连接,而在另一种情况下它应该打破连接?我现在正在考虑外部连接。
    • @galaxy0208 请再看回复,如果你的Oracle版本支持join关键字就更新2,不支持就更新1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 2012-02-22
    • 2021-08-20
    相关资源
    最近更新 更多