是否可以动态跳过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_compare
和age_compare_group
都为空,则应该给出所有结果。
如果其中任何一个不为null,那么它应该根据查询的部分显示结果。
如果我可以做同样的其他事情,请告诉我。
答案 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包装到一个函数中,以便更容易显示一些测试:
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)
)
);