动态跳过Where子句

时间:2013-12-03 07:03:55

标签: sql database oracle dynamic where

是否可以动态跳过where子句?

我正在努力实现这一目标。

select count(*)
      into user_count
from mstuser a
where ((gender_compare is not null or gender_compare != '') 
   and upper(a.gender)=upper(gender_compare)) 
   and (age_compare_group is not null or age_compare_group != '') 
   and (MONTHS_BETWEEN(sysdate, a.dob) / 12 
        between substr(age_compare_group, 0, INSTR(age_compare_group, '-') - 1) 
            and substr(age_compare_group, INSTR(age_compare_group, '-') + 1)))

但它似乎无效。

我想要的是:

如果值gender_compareage_compare_group都为空,则应该给出所有结果。 如果其中任何一个不为null,那么它应该根据查询的部分显示结果。

如果我可以做同样的其他事情,请告诉我。

3 个答案:

答案 0 :(得分:4)

看起来你要做的就是将你的病情分成两组

WHERE (gender_compare IS NULL OR gender_compare = '')
      OR (<the rest of condition>)

如果genter_compare IS NULL评估为TRUE,则整个条件为TRUE,因此WHERE子句将等同于WHERE TRUE,这相当于否WHERE声明。

否则,第二个条件将生效。

答案 1 :(得分:2)

我已将SQL包装到一个函数中,以便更容易显示一些测试:

SQL Fiddle

Oracle 11g R2架构设置

CREATE TABLE mstuser ( id, gender, dob ) AS
          SELECT 1, 'M', SYSDATE - INTERVAL '1' YEAR FROM DUAL
UNION ALL SELECT 2, 'M', SYSDATE - INTERVAL '2' YEAR FROM DUAL
UNION ALL SELECT 3, 'M', SYSDATE - INTERVAL '3' YEAR FROM DUAL
UNION ALL SELECT 4, 'F', SYSDATE - INTERVAL '1' YEAR FROM DUAL
UNION ALL SELECT 5, 'F', SYSDATE - INTERVAL '2' YEAR FROM DUAL
UNION ALL SELECT 6, 'F', SYSDATE - INTERVAL '3' YEAR FROM DUAL
UNION ALL SELECT 7, 'F', SYSDATE - INTERVAL '4' YEAR FROM DUAL
UNION ALL SELECT 8, 'F', SYSDATE - INTERVAL '5' YEAR FROM DUAL
/

CREATE OR REPLACE FUNCTION count_by_compare (
  gender_compare    mstuser.gender%TYPE,
  age_compare_group VARCHAR2
) RETURN NUMBER
AS
  user_count NUMBER;
BEGIN
  SELECT COUNT(1)
  INTO   user_count
  FROM   mstuser a
  WHERE  (   gender_compare IS NULL
          OR UPPER( a.gender ) = UPPER(gender_compare)
         ) 
  AND    (   age_compare_group IS NULL
          OR MONTHS_BETWEEN(sysdate, a.dob) / 12 
             BETWEEN TO_NUMBER( SUBSTR(age_compare_group, 1, INSTR(age_compare_group, '-') - 1) )
                 AND TO_NUMBER( SUBSTR(age_compare_group, INSTR(age_compare_group, '-') + 1) )
         );
  return user_count;
END;
/

查询1

WITH Tests AS (
            SELECT 'M' AS gender, '0-1' AS age FROM DUAL
  UNION ALL SELECT 'F', '0-6' FROM DUAL
  UNION ALL SELECT 'F', '0-1' FROM DUAL
  UNION ALL SELECT 'M', '0-6' FROM DUAL
  UNION ALL SELECT NULL, '0-2' FROM DUAL
  UNION ALL SELECT 'M', NULL FROM DUAL
  UNION ALL SELECT 'F', NULL FROM DUAL
  UNION ALL SELECT NULL, NULL FROM DUAL
  UNION ALL SELECT '', '' FROM DUAL
)
SELECT gender,
       age,
       SUBSTR(age, 1, INSTR(age, '-') - 1),
       SUBSTR(age, INSTR(age, '-') + 1),
       count_by_compare( gender, age )
FROM   Tests

<强> Results

| GENDER |    AGE | SUBSTR(AGE,1,INSTR(AGE,'-')-1) | SUBSTR(AGE,INSTR(AGE,'-')+1) | COUNT_BY_COMPARE(GENDER,AGE) |
|--------|--------|--------------------------------|------------------------------|------------------------------|
|      M |    0-1 |                              0 |                            1 |                            1 |
|      F |    0-6 |                              0 |                            6 |                            5 |
|      F |    0-1 |                              0 |                            1 |                            1 |
|      M |    0-6 |                              0 |                            6 |                            3 |
| (null) |    0-2 |                              0 |                            2 |                            4 |
|      M | (null) |                         (null) |                       (null) |                            3 |
|      F | (null) |                         (null) |                       (null) |                            5 |
| (null) | (null) |                         (null) |                       (null) |                            8 |
| (null) | (null) |                         (null) |                       (null) |                            8 |

此外,您不需要测试!= '',因为oracle将空字符串表示为NULL - 请参阅上面的最终测试或下面的空字符串比较:

SELECT CASE WHEN '' = '' THEN 1 ELSE 0 END AS equal,
       CASE WHEN '' != '' THEN 1 ELSE 0 END AS not_equal,
       CASE WHEN '' IS NULL THEN 1 ELSE 0 END AS is_null,
       CASE WHEN '' IS NOT NULL THEN 1 ELSE 0 END AS is_not_null
FROM DUAL

给出结果:

| EQUAL | NOT_EQUAL | IS_NULL | IS_NOT_NULL |
|-------|-----------|---------|-------------|
|     0 |         0 |       1 |           0 |

答案 2 :(得分:0)

当gender_compare不为null时,通常会与gender_compare进行比较,而当age_compare_group不为null时,则与age_compare_group进行比较。您也可以这样说:“要么gender_compare为null,要么与之进行比较”和“age_compare_group为null或我与之进行比较”。这就是你如何相应地编写select语句:

select count(*)
  into user_count
from mstuser a
where 
( 
  gender_compare is null 
 or 
  upper(a.gender) = upper(gender_compare)
) -- compare gender if given
and
( 
  age_compare_group is null 
 or 
  months_between(sysdate, a.dob) / 12 
     between substr(age_compare_group, 0, instr(age_compare_group, '-') - 1) 
     and substr(age_compare_group, instr(age_compare_group, '-') + 1)
);

但是,如果你真的只想在给出两者的情况下与gender_compare和age_compare_group进行比较,并且如果只给出其中一个或者没有一个(即至少其中一个为空),则根本不进行比较,那么它是这样的:

select count(*)
  into user_count
from mstuser a
where 
( 
  (
    gender_compare is null 
   or 
    age_compare_group is null
  )
 or 
  (
    upper(a.gender) = upper(gender_compare)
   and
    months_between(sysdate, a.dob) / 12 
       between substr(age_compare_group, 0, instr(age_compare_group, '-') - 1) 
       and substr(age_compare_group, instr(age_compare_group, '-') + 1)
    )
);