我正在使用Node-RED和DashDB开发IBM Bluemix解决方案。在将ACCOUNT_ID
SQL子句上的多个值解析为名为WHERE IN
的列时,我遇到了一个问题。如果我只传递一个参数它可以正常工作,但是当我有两个或更多参数时,它会失败并显示以下错误消息:
msg.account = msg.req.query.account;
msg.datestart = msg.req.query.datestart;
msg.dateend = msg.req.query.dateend;
var strPayload = "SELECT A.*, B.DESCRIPTION AS ACCOUNT_NAME, C.DESCRIPTION AS TYPE_NAME ";
strPayload += " FROM NORMALIZED_TABLE A ";
strPayload += " INNER JOIN ACCOUNT B ON A.ACCOUNT_ID = B.ACCOUNT_ID ";
strPayload += " INNER JOIN NORMALIZED_TYPE C ON A.TYPE_ID = C.TYPE_ID";
strPayload += " WHERE A.ACCOUNT_ID IN(?) AND DATE_START>=? AND DATE_END<=?";
strPayload += " FETCH FIRST 1000 ROWS ONLY";
msg.payload = strPayload;
return msg;
基本上我的问题在于:WHERE A.ACCOUNT_ID IN(?)
。使用单个值,可以调用Web服务,它可以正常工作,如下所示:
/getPreviewReport?datestart=2016-08-01&dateend=2016-08-01&account=44
但是当我为帐户参数传递多个值时,它会失败:
/getPreviewReport?datestart=2016-08-01&dateend=2016-08-01&account=44,45,2
节点红色错误:
dashDB查询节点:错误:[IBM] [CLI驱动程序] [DB2 / LINUXX8664] SQL0420N在函数&#34; DECIMAL&#34;的字符串参数中找到无效字符。 SQLSTATE = 22018
我如何解决这个问题?
答案 0 :(得分:0)
我所知道的任何SQL数据库都将把作为绑定变量值提供的任何内容视为单个值 - 没有任何解析。
处理可变长度IN
列表的常用方法是使用动态SQL,遗憾的是,它很容易受到SQL注入攻击,特别是在像你这样的场景中,你将未经过处理的HTTP请求属性直接传递给查询。
您可以通过使用递归SQL来解析参数字符串来添加一些安全性,如下所示:
-- parse comma-separated values into a "table"
WITH lst (lvl, id, tail) AS (
SELECT 1, CASE WHEN LOCATE(',',input) > 0
THEN TRIM(LEFT(input, LOCATE(',',input)-1))
ELSE TRIM(input)
END,
CASE WHEN LOCATE(',',input) > 0
THEN SUBSTR(input, LOCATE(',',input)+1)
ELSE ''
END
FROM table (values ?) as (input)
UNION ALL
SELECT lvl + 1, CASE WHEN LOCATE(',', tail) > 0
THEN TRIM(LEFT(tail, LOCATE(',', tail)-1))
ELSE TRIM(tail)
END,
CASE WHEN LOCATE(',', tail) > 0
THEN SUBSTR(tail, LOCATE(',', tail)+1)
ELSE ''
END
FROM lst
WHERE lvl < 100 AND tail != '')
SELECT a.*, b.description as account_name, c.description as type_name
FROM normalized_table a
INNER JOIN account b ON a.account_id = b.account_id
INNER JOIN normalized_type c ON a.type_id = c.type_d
-- join to the parameter "table" on id
INNER JOIN lst ON a.account_id = lst.id
WHERE date_start>=? AND date_nd<=?
FETCH FIRST 1000 ROWS ONLY