动态处理选择条件

时间:2014-04-10 04:38:08

标签: sql oracle select plsql

我有一个类似

的程序
Procedure P_GENDER_REP
 (
  l_province  IN  varchar,
  l_district  IN  varchar,
  l_village   IN  varchar,
  l_tribe     IN  varchar,
  l_clan      IN  varchar,
  l_refcursor out sys_refcursor
 )

我在这个程序中有一个选择查询

select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
from itaukei_data_store b,itaukei_data_store_key a 
where a.reference_no = b.reference_no and a.record_no = b.record_no and a.province = l_province 
  and a.district = l_district and a.village = l_village and a.tribe= l_tribe 
    and a.clan = l_clan      
order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;

现在我需要一个处理给定输入的select查询。例如,如果只给出l_province,我需要忽略动态条件的所有其他。请帮助我。

4 个答案:

答案 0 :(得分:1)

通常您可以通过在每个条件中添加OR l_variable IS NULL来执行此操作:

select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
from itaukei_data_store b INNER JOIN itaukei_data_store_key a 
ON a.reference_no = b.reference_no 
  and a.record_no = b.record_no 
  and a.province = l_province 
WHERE l_district IS NULL OR a.district = l_district
  and l_village IS NULL OR a.village = l_village
  and l_tribe IS NULL OR a.tribe= l_tribe
  and l_clan IS NULL OR a.clan = l_clan
order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;

但是,这有时会影响性能。最好为每种组合使用IF。或者,您可以尝试使用支持短路的CASE语句,如下所示:

select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
from itaukei_data_store b INNER JOIN itaukei_data_store_key a 
ON a.reference_no = b.reference_no 
  and a.record_no = b.record_no 
  and a.province = l_province 
WHERE a.district = CASE WHEN l_district IS NULL THEN a.district ELSE l_district END
  and a.village = CASE WHEN l_village IS NULL THEN a.village ELSE l_village END
  and a.tribe = CASE WHEN l_tribe IS NULL THEN a.tribe ELSE l_tribe END
  and a.clan = CASE WHEN l_clan IS NULL THEN a.clan ELSE l_clan END
order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;

你有第三种选择。您可以使用COALESCE代替CASE,如下所示:

select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
from itaukei_data_store b INNER JOIN itaukei_data_store_key a 
ON a.reference_no = b.reference_no 
  and a.record_no = b.record_no 
  and a.province = l_province 
WHERE a.district = COALESCE(l_district, a.district)
  and a.village = COALESCE(l_village, a.village)
  and a.tribe = COALESCE(l_tribe, a.tribe)
  and a.clan = COALESCE(l_clan, a.clan)
order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;

尝试每一个,看看哪个表现更好。顺便说一下,我还将FROM子句从逗号分隔的表列表更改为标准的INNER JOIN。请养成使用JOIN的习惯,因为它现在被认为是最好的parctice"

答案 1 :(得分:0)

给出的例子是SQL Server, 第一种方式,简单如果

Declare @l_province int
Declare @l_district int
Declare @l_village int

If @l_province is not null and @l_district is null  and @l_village is null -- Only l_province is given
Begin
    select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
        from itaukei_data_store b,itaukei_data_store_key a 
    order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;
End
Else
Begin
    select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
        from itaukei_data_store b,itaukei_data_store_key a 
    where a.reference_no = b.reference_no 
            and a.record_no = b.record_no 
            and a.province = l_province 
            and a.district = l_district 
            and a.village = l_village 
            and a.tribe= l_tribe 
            and a.clan = l_clan      
    order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;
End

---------------------使用OR,AND的第二种方式

select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data 
        from itaukei_data_store b,itaukei_data_store_key a 
    where (
            (
                (@l_province is not null and @l_district is null  and @l_village is null) -- Only l_province is given
                AND
                (1=1)
            )
            OR
            (
                (@l_province is not null and (@l_district is not null  OR @l_village is not null))
                AND
                (
                        a.reference_no = b.reference_no 
                        and a.record_no = b.record_no 
                        and a.province = l_province 
                        and a.district = l_district 
                        and a.village = l_village 
                        and a.tribe= l_tribe 
                        and a.clan = l_clan 
                )
            )
            OR
            (
                (@l_province is null)
                AND
                (
                        a.reference_no = b.reference_no 
                        and a.record_no = b.record_no 
                        and a.province = l_province 
                        and a.district = l_district 
                        and a.village = l_village 
                        and a.tribe= l_tribe 
                        and a.clan = l_clan 
                )

            )
        )   
    order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;

实际上为了使存储过程变得简单,我建议你带一个应该使用where子句的参数!要计算该变量,您需要在代码后面或存储过程开始时编写一些代码。它会让生活变得轻松。

答案 2 :(得分:0)

只是为了添加另一个黑客。

如果您对每个列都没有类似的值,则可以使用coalesce

select  a.province,a.district,a.village,a.tribe,a.clan,b.cdr_data 
from    itaukei_data_store b,itaukei_data_store_key a 
where   a.reference_no = b.reference_no 
and     a.record_no = b.record_no 
and     coalesce(a.province,a.district,a.village,a.tribe,a.clan) = 
        coalesce(l_province,l_district,l_village,l_tribe,l_clan)
order by a.district,a.village,a.tribe,a.clan;

Coalesce返回列表中的第一个not null值

答案 3 :(得分:0)

你可以调整这些参数,这样当它们被设置时,它们就会被使用,否则就会得到比较表中的匹配值..应该具有预期的效果:

select a.province,a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN,b.cdr_data
from itaukei_data_store b,itaukei_data_store_key a 
where a.reference_no = b.reference_no 
and a.record_no = b.record_no 
and a.province = nvl(l_province, a.province)
and a.district = nvl(l_district, a.district)
and a.village = nvl(l_village, a.village)
and a.tribe = nvl(l_tribe, a.tribe) 
and a.clan = nvl(l_clan, a.clan)
order by a.DISTRICT,a.VILLAGE,a.TRIBE,a.CLAN;