我尝试使用this link使用安全的SQL脚本,但是当动态绑定变量的数量越来越多时,代码似乎很笨拙。请检查此代码并提出降低复杂性的想法。
根据下面的代码,您可以看到这三个变量(ZONE_CODE_STR,ACTIVE_STR和LOGICAL_ENV_STR)作为查询的参数,当值到来时我使用它们或者用空字符串替换它们。但问题是当我想要的时候添加一个参数,IF-ELSE逻辑变得太复杂。如果我想再增加一个新的动态变量,请帮我找一个简单的方法。
代码示例:
-- APPLICATION VARIABLES STARTS HERE
ZONE_CODE_STR VARCHAR2(100);
ZONE_CODE_FLAG VARCHAR2(20);
ACTIVE_STR VARCHAR2(100);
ACTIVE_FLAG VARCHAR2(20);
LOGICAL_ENV_STR VARCHAR2(100);
LOGICAL_ENV_FLAG VARCHAR2(20);
QUERY_STR VARCHAR2(4000);
-- APPLICATION VARIABLES END HERE
BEGIN
-- APPLICATION LOGIC STARTS HERE
ZONE_CODE_STR := ' AND ZONE_ENV_CODE IN (: IN_ZONE_ENV_CODE)';
ZONE_CODE_FLAG := '@@ZONE_CODE@@';
LOGICAL_ENV_STR := ' AND LOGICAL_DB_ENVIRONMENT.ZONE_ENV_CODE IN(: IN_ZONE_ENV_CODE)';
LOGICAL_ENV_FLAG := '@@LOGICAL_ENV@@';
ACTIVE_STR := ' AND ACTIVE =: IN_ACTIVE';
ACTIVE_FLAG := '@@ACTIVE@@';
QUERY_STR :='SELECT
RES_DETAIL.FRAME_NAME,RES_DETAIL.LISTENER_PORT,
RES_DETAIL.PROPERTY_NAME,RES_DETAIL.PROPERTY_VALUE,RES_DETAIL.IP_ADDRESS,
TEST_APP_ENTRIES.*,
TEST_APP_WEB_SERVER_TYPE.APP_WEB_SERVER_TYPE_NAME,
TEST_OPERATION_TYPE.OPERATION_TYPE_NAME,
TEST_SINGLE_SIGN_ON.SINGLE_SIGN_ON_NAME,TEST_APP_REALM_ENTRIES.WARE_ID,TEST_APP_REALM_ENTRIES.RESOURCE_FILTER,
TEST_APP_REALM_ENTRIES.PROTECTION_STATUS, TEST_APP_REALM_ENTRIES.AUTHENTICATION_TYPE_ID,
TEST_AUTHENTICATION_TYPE.AUTHENTICATION_TYPE_NAME,
TEST_APP_REALM_ENTRIES.ROLE
FROM
(
SELECT * FROM TEST_APP_ENTRIES WHERE APP_EXT_CODE =: IN_APP_EXT_CODE
@@ZONE_CODE@@
@@ACTIVE@@
)TEST_APP_ENTRIES
INNER JOIN
TEST_APP_REALM_ENTRIES
ON
TEST_APP_ENTRIES.WAE_ID = TEST_APP_REALM_ENTRIES.WAE_ID
INNER JOIN
TEST_OPERATION_TYPE
ON
TEST_APP_ENTRIES.OPERATION_TYPE_ID = TEST_OPERATION_TYPE.OPERATION_TYPE_ID
INNER JOIN
TEST_APP_WEB_SERVER_TYPE
ON
TEST_APP_ENTRIES.APP_WEB_SERVER_TYPE_ID = TEST_APP_WEB_SERVER_TYPE.APP_WEB_SERVER_TYPE_ID
INNER JOIN
TEST_SINGLE_SIGN_ON
ON
TEST_APP_ENTRIES.SINGLE_SIGN_ON_ID = TEST_SINGLE_SIGN_ON.SINGLE_SIGN_ON_ID
INNER JOIN
TEST_AUTHENTICATION_TYPE
ON
TEST_APP_REALM_ENTRIES.AUTHENTICATION_TYPE_ID = TEST_AUTHENTICATION_TYPE.AUTHENTICATION_TYPE_ID
RIGHT OUTER JOIN
(SELECT APP_FRAMES.LOGICAL_DB_ENV_NAME AS LOGICAL_DB_ENV_NAME,APP_FRAME_PROPERTIES.FRAME_NAME AS FRAME_NAME,APP_FRAME_PROPERTIES.APP_EXT_CODE AS APP_EXT_CODE,FRAMES.LISTENER_PORT AS LISTENER_PORT,
LOGICAL_DB_ENVIRONMENT.ZONE_ENV_CODE AS ZONE_ENV_CODE,
APP_FRAME_PROPERTIES.PROPERTY_NAME AS PROPERTY_NAME,APP_FRAME_PROPERTIES.PROPERTY_VALUE AS PROPERTY_VALUE,NODES.IP_ADDRESS AS IP_ADDRESS
FROM APP_FRAME_PROPERTIES,NODES,FRAMES,APP_FRAMES,LOGICAL_DB_ENVIRONMENT
WHERE APP_FRAME_PROPERTIES.FRAME_NAME = FRAMES.FRAME_NAME
AND APP_FRAME_PROPERTIES.APP_EXT_CODE = APP_FRAMES.APP_EXT_CODE
AND LOGICAL_DB_ENVIRONMENT.APP_EXT_CODE = APP_FRAMES.APP_EXT_CODE
AND LOGICAL_DB_ENVIRONMENT.LOGICAL_DB_ENV_NAME = APP_FRAMES.LOGICAL_DB_ENV_NAME
AND APP_FRAME_PROPERTIES.LOGICAL_DB_ENV_NAME = APP_FRAMES.LOGICAL_DB_ENV_NAME
AND NODES.FRAME_NAME = APP_FRAME_PROPERTIES.FRAME_NAME
AND APP_FRAMES.FRAME_NAME = APP_FRAME_PROPERTIES.FRAME_NAME
AND APP_FRAMES.APP_EXT_CODE =: IN_APP_EXT_CODE
@@LOGICAL_ENV@@
) RES_DETAIL
ON
TEST_APP_ENTRIES.APP_EXT_CODE = RES_DETAIL.APP_EXT_CODE
AND TEST_APP_ENTRIES.ZONE_ENV_CODE = RES_DETAIL.ZONE_ENV_CODE ORDER BY TEST_APP_ENTRIES.WAE_ID,WARE_ID';
IF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'UAT') THEN
IN_ZONE_ENV_CODE := 'DEV';
ELSIF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'PROD') THEN
IN_ZONE_ENV_CODE := 'UAT';
END IF;
IF(IN_ZONE_ENV_CODE IS NULL OR IN_ZONE_ENV_CODE = '' OR IN_ZONE_ENV_CODE = 'ALL') THEN
QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,'');
QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,'');
IF(IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_APP_EXT_CODE;
ELSE
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ACTIVE,IN_APP_EXT_CODE;
END IF;
ELSIF (IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;
ELSE
QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_ACTIVE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;
END IF;
答案 0 :(得分:2)
我认为您可以使用以下静态sql执行您所需的操作:
add_item_sorted
因此,您之前测试的参数是否为null,然后在适当的位置将其构建到where子句中,而是将其替换为cur->next->data
您必须使用您的数据进行测试,以确保效果仍然令人满意。
附加说明:
select res_detail.frame_name,
res_detail.listener_port,
res_detail.property_name,
res_detail.property_value,
res_detail.ip_address,
test_app_entries.*,
test_app_web_server_type.app_web_server_type_name,
test_operation_type.operation_type_name,
test_single_sign_on.single_sign_on_name,
test_app_realm_entries.ware_id,
test_app_realm_entries.resource_filter,
test_app_realm_entries.protection_status,
test_app_realm_entries.authentication_type_id,
test_authentication_type.authentication_type_name,
test_app_realm_entries.role
from (select *
from test_app_entries
where app_ext_code = in_app_ext_code
and (zone_env_code = in_zone_env_code or in_zone_env_code is null) -- changed
and (active = in_active or in_active is null) -- changed
) test_app_entries
inner join test_app_realm_entries on test_app_entries.wae_id = test_app_realm_entries.wae_id
inner join test_operation_type on test_app_entries.operation_type_id = test_operation_type.operation_type_id
inner join test_app_web_server_type on test_app_entries.app_web_server_type_id = test_app_web_server_type.app_web_server_type_id
inner join test_single_sign_on on test_app_entries.single_sign_on_id = test_single_sign_on.single_sign_on_id
inner join test_authentication_type on test_app_realm_entries.authentication_type_id = test_authentication_type.authentication_type_id
right outer join (select app_frames.logical_db_env_name as logical_db_env_name,
app_frame_properties.frame_name as frame_name,
app_frame_properties.app_ext_code as app_ext_code,
frames.listener_port as listener_port,
logical_db_environment.zone_env_code as zone_env_code,
app_frame_properties.property_name as property_name,
app_frame_properties.property_value as property_value,
nodes.ip_address as ip_address
from app_frame_properties,
nodes,
frames,
app_frames,
logical_db_environment
where app_frame_properties.frame_name = frames.frame_name
and app_frame_properties.app_ext_code = app_frames.app_ext_code
and logical_db_environment.app_ext_code = app_frames.app_ext_code
and logical_db_environment.logical_db_env_name = app_frames.logical_db_env_name
and app_frame_properties.logical_db_env_name = app_frames.logical_db_env_name
and nodes.frame_name = app_frame_properties.frame_name
and app_frames.frame_name = app_frame_properties.frame_name
and app_frames.app_ext_code = in_app_ext_code
and (logical_db_environment.zone_env_code = in_zone_env_code or in_zone_env_code is null) -- changed
) res_detail on test_app_entries.app_ext_code = res_detail.app_ext_code
and test_app_entries.zone_env_code = res_detail.zone_env_code
order by test_app_entries.wae_id, ware_id;
缺少别名。它来自哪个表?(parameter = some_col or parameter is null)
- 在生产代码中,在外部选择中使用*是个坏主意;如果有人添加了一个列会发生什么?一般情况下,最好尽可能避免使用动态sql - 如果不将其他文本连接到sql语句中,则不会出现安全问题,而且通常它更易于维护和调试。
答案 1 :(得分:1)
在上面的PL SQL中, 在其中一些中使用BIND VARIABLES
,但是,您仍在使用连接创建动态SQL(在这种情况下使用REPLACE
功能)。您提供的查询相当大而且复杂,因此我将仅使用它的简化选择为您提供示例。
-- Your stripped-down code:
ZONE_CODE_STR := ' AND ZONE_ENV_CODE IN ( :IN_ZONE_ENV_CODE )';
ZONE_CODE_FLAG := '@@ZONE_CODE@@';
ACTIVE_STR := ' AND ACTIVE = :IN_ACTIVE ';
ACTIVE_FLAG := '@@ACTIVE@@';
QUERY_STR :='SELECT * FROM TEST_APP_ENTRIES WHERE APP_EXT_CODE = :IN_APP_EXT_CODE @@ZONE_CODE@@ @@ACTIVE@@ ';
IF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'UAT') THEN
IN_ZONE_ENV_CODE := 'DEV';
ELSIF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'PROD') THEN
IN_ZONE_ENV_CODE := 'UAT';
END IF;
IF(IN_ZONE_ENV_CODE IS NULL OR IN_ZONE_ENV_CODE = '' OR IN_ZONE_ENV_CODE = 'ALL') THEN
QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,'');
QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,'');
IF(IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_APP_EXT_CODE;
ELSE
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ACTIVE,IN_APP_EXT_CODE;
END IF;
ELSIF (IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;
ELSE
QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_ACTIVE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;
END IF;
我建议做的是重构你的实际SQL查询,以消除与需要动态重写查询相关的额外PL / SQL代码(如果不是全部的话)...在下面的代码中我将解释发生了什么:
SELECT * FROM TEST_APP_ENTRIES
WHERE APP_EXT_CODE = IN_APP_EXT_CODE
AND CASE Coalesce(:IN_ZONE_ENV_CODE, 'ALL') -- See Note 1 below...
WHEN 'ALL' THEN ZONE_ENV_CODE
ELSE :IN_ZONE_ENV_CODE
END = ZONE_ENV_CODE
AND Coalesce(:IN_ACTIVE, ACTIVE) = ACTIVE; -- See Note 2 below...
注1:我们可以使用COALESCE
函数(它返回逗号中的第一个非空项),而不是检查变量为null然后替换占位符。已分隔的列表),并将WHEN
部分与'ALL'
的字面值进行比较(如果TRUE
变量为{{{}},我们将在比较中评估:IN_ACTIVE
1}}或它实际上包含NULL
)的值,我们将使用ALL
,否则如果不评估ZONE_ENV_CODE
,我们会转到TRUE
部分{ {1}}并改为使用ELSE
。然后将其中一个与WHEN
进行比较。这意味着,如果:IN_ZONE_ENV_CODE
是ZONE_ENV_CODE
或:IN_ZONE_ENV_CODE
,我们会在where子句中使用NULL
,否则我们会使用ALL
。
注2:相似但更简单......如果ZONE_ENV_CODE = ZONE_ENV_CODE
为:IN_ZONE_ENV_CODE = ZONE_ENV_CODE
,我们只需使用COALESCE
来比较ACTIVE = ACTIVE
,否则{{1 }}