提问人:Vidya 提问时间:8/17/2023 最后编辑:JamesVidya 更新时间:8/27/2023 访问量:51
如何将 SQL 查询更改为参数化查询
How to change SQL query to a parameterized query
问:
let query =
select * from (select acf.ID "call_flow_ID", acf.Name "CALL_FLOW_NAME", acf.SLO "SERVICE_OBJECTIVE", acf.LOG_FILTER "LOG_FILTER", acf.Max_jump,
(SELECT LISTAGG(NAME, ',') WITHIN GROUP (ORDER BY name) FROM ACR_SUBROUTINE acs RIGHT JOIN ACR_CALL_FLOW_SUB ON SUB_ID=acs.ID WHERE FLOW_ID=acf.ID AND TYPE IN ('ANC') GROUP BY TYPE) "ANNOUNCEMENT_TREATMENT",
(SELECT NAME FROM ACR_USER_DOMAIN aud WHERE aud.DOMAIN_ID=acf.DOMAIN_ID) "DOMAIN_NAME",
(SELECT DOMAIN_ID FROM ACR_USER_DOMAIN aud WHERE aud.DOMAIN_ID=acf.DOMAIN_ID) "DOMAIN_ID",
(
SELECT LISTAGG(name,',') WITHIN GROUP (ORDER BY name)
FROM ACR_VIRTUAL_QUEUE
WHERE FLOW_ID=acf.id
GROUP BY FLOW_ID
) "VIRTUAL_QUEUE",
(select outerHeight.name ofchrset
from
acr_call_flow false,
acr_cf_hs hs,
acr_holiday_set s,
acr_office_day od,
acr_office_day_set Os,
acr_office_hour_set oh
WHERE
od.flow_id = f.id and
hs.flow_id(+) =f.id and
hs.hs_id= s.id(+) and
oh.id=os.ohs.id and
os.od_id=od.id and
f.id=acf.id
) "OFFICE_HOUR_SET"
from ACR_CALL_FLOW acf)`;
let whereConstant = "";
let whereString = "";
let hasMoreThanOneCondition = false;
let parameterizedQueryObjects = [];
req.body.searchFields.forEach((field) => {
whereConstant = " WHERE ";
if (hasMoreThanOneCondition) {
whereString += req.body.checkAll ? "AND" : "OR";
}
let checkfield = field.value.toUpperCase();
if (checkfield == "DEBUG") {
field.VALUE = "3";
}
if (checkfield == "ERROR") {
field.VALUE = "2";
}
if (checkfield == "INFO") {
field.VALUE = "1";
}
if (checkfield == "WARN") {
field.VALUE = "0";
}
whereString += `UPPER(${field.field})`;
switch (field.operator) {
case "EQUALS":
case "CONTAINS":
whereString += `LIKE '%' || UPPER(:${field.field}) || '%'`;
break;
case "DOESNT_EQUALS":
case "DOESNT_CONTAIN":
whereString += `NOT LIKE UPPER(:${field.field}) || '%'`;
break;
case "STARTS_WITH":
whereString += ` LIKE UPPER(:${field.field}) || '%'`;
break;
}
parameterizedQueryObjects.push(field.value.replace(/\*/g, "%"));
hasMoreThanOneCondition = true;
});
let results = await Connection.execute(
query + (whereString !== "" ? whereConstant + whereString : ""),
parameterizedQueryObjects,
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
).catch((err) => {
throw err;
});
普通 SQL 查询:
let sqlcheckGroupName = `select COUNT(*) FROM ACR_GROUP WHERE UPPER(NAME) = UPPER(${group})`;
let checkGroupName = await connection.execute(sqlCheckGroupName, {})
转换为参数化查询:
let sqlcheckGroupName = `select COUNT(*) FROM ACR_GROUP WHERE UPPER(NAME) = UPPER(:group)`;
let checkGroupName = await connection.execute(sqlCheckGroupName, {group: group});
在上面提到的中,我举了一个例子,说明如何将普通查询更改为参数化查询。同样,我想知道如何将具有开关大小写语句的查询更改为参数化查询?
我是SQL的新手,我不太擅长编写查询。
答:
0赞
Adrian Maxwell
8/18/2023
#1
我不是要回答参数化问题,而是利用这个机会指出您当前查询中的一些问题:
此子查询引用但该表未在其他任何地方提及,因此它应该失败:outerHeight.name
, (
SELECT outerHeight.name ofchrset
FROM acr_call_flow false
, acr_cf_hs hs
, acr_holiday_set s
, acr_office_day od
, acr_office_day_set Os
, acr_office_hour_set oh
WHERE od.flow_id = f.id
AND hs.flow_id(+) = f.id
AND hs.hs_id = s.id(+)
AND oh.id = os.ohs.id
AND os.od_id = od.id
AND f.id = acf.id
) "OFFICE_HOUR_SET"
而且该子查询使用的是古老的连接语法,实际上不应该再使用。(+)
更广泛地说,您正在使用许多“相关子查询”,这些子查询因性能差(缓慢)而臭名昭著:
SELECT *
FROM (
SELECT acf.ID "call_flow_ID"
, acf.Name "CALL_FLOW_NAME"
, acf.SLO "SERVICE_OBJECTIVE"
, acf.LOG_FILTER "LOG_FILTER"
, acf.Max_jump
, ( /* this would be more efficient as a joined subquery */
SELECT LISTAGG(NAME, ',') WITHIN
GROUP (
ORDER BY name
)
FROM ACR_SUBROUTINE acs
RIGHT JOIN ACR_CALL_FLOW_SUB ON SUB_ID = acs.ID
WHERE FLOW_ID = acf.ID
AND TYPE IN ('ANC')
GROUP BY TYPE
) "ANNOUNCEMENT_TREATMENT"
, ( /* this runs the risk of returning more than 1 row which would produce an eror */
/* you may be able to left join this table to get the same outcome */
SELECT NAME
FROM ACR_USER_DOMAIN aud
WHERE aud.DOMAIN_ID = acf.DOMAIN_ID
) "DOMAIN_NAME"
, ( /* this runs the risk of returning more than 1 row which would produce an eror */
/* you may be able to left join this table to get the same outcome */
SELECT DOMAIN_ID
FROM ACR_USER_DOMAIN aud
WHERE aud.DOMAIN_ID = acf.DOMAIN_ID
) "DOMAIN_ID"
, ( /* this would be more efficient as a joined subquery */
SELECT LISTAGG(name, ',') WITHIN
GROUP (
ORDER BY name
)
FROM ACR_VIRTUAL_QUEUE
WHERE FLOW_ID = acf.id
GROUP BY FLOW_ID
) "VIRTUAL_QUEUE"
, ( /* unless you run an ancient version of Oracle STOP using ANTIQUE (+) syntax */
SELECT outerHeight.name ofchrset
FROM acr_call_flow false
, acr_cf_hs hs
, acr_holiday_set s
, acr_office_day od
, acr_office_day_set Os
, acr_office_hour_set oh
WHERE od.flow_id = f.id
AND hs.flow_id(+) = f.id
AND hs.hs_id = s.id(+)
AND oh.id = os.ohs.id
AND os.od_id = od.id
AND f.id = acf.id
) "OFFICE_HOUR_SET"
FROM ACR_CALL_FLOW acf
)
我建议重写(但当然未经测试)
SELECT *
FROM (
SELECT acf.ID "call_flow_ID"
, acf.Name "CALL_FLOW_NAME"
, acf.SLO "SERVICE_OBJECTIVE"
, acf.LOG_FILTER "LOG_FILTER"
, acf.Max_jump
, acs.ANNOUNCEMENT_TREATMENT
, aud.NAME "DOMAIN_NAME"
, aud.DOMAIN_ID
, avq.VIRTUAL_QUEUE
/* ancient syntax sub-query removed as it is incomplete, see under for more */
--, aod.OFFICE_HOUR_SET
FROM ACR_CALL_FLOW acf
LEFT JOIN ACR_USER_DOMAIN aud ON aud.DOMAIN_ID = acf.DOMAIN_ID
LEFT JOIN (
SELECT FLOW_ID, LISTAGG(NAME, ',') WITHIN GROUP ( ORDER BY name ) "ANNOUNCEMENT_TREATMENT"
FROM ACR_SUBROUTINE acs
RIGHT JOIN ACR_CALL_FLOW_SUB ON SUB_ID = acs.ID /* is right join really neccessary */
WHERE TYPE IN ('ANC')
GROUP BY FLOW_ID
) acs ON acs.FLOW_ID = acf.ID
LEFT JOIN (
SELECT FLOW_ID, LISTAGG(name, ',') WITHIN GROUP ( ORDER BY name ) "VIRTUAL_QUEUE"
FROM ACR_VIRTUAL_QUEUE
GROUP BY FLOW_ID
) avq ON FLOW_ID = acf.id
)
将“相关子查询”替换为左联接允许返回 NULL(这等效于原始子查询的行为方式)。但是,如果联接中有超过 1 行匹配,那么您将获得比以前更多的行(但要避免原始子查询在返回超过 1 行时会导致的错误)。
最后一个子查询似乎是错误的或不完整的,这是我删除古老语法所能做的最好的事情:
LEFT JOIN (
SELECT f.id, outerHeight.name "OFFICE_HOUR_SET"
FROM acr_call_flow f
INNER JOIN acr_office_day od ON od.flow_id = f.id
INNER JOIN acr_office_day_set os ON os.od_id = od.id
INNER JOIN acr_office_hour_set oh ON oh.id = os.ohs.id
LEFT JOIN acr_cf_hs hs ON hs.flow_id = f.id
LEFT JOIN acr_holiday_set s ON s.id = hs.hs_id
) aod ON aod.id = acf.id
请注意,您很有可能不需要所有这些表(尤其是左连接),但您必须解决问题 - 也许是别名吗?outerHeight
oh
评论