2016-09-06 97 views
0

我正在使用Node-RED和DashDB開發IBM Bluemix解決方案。將多個值解析爲WHERE IN SQL子句中名爲ACCOUNT_ID的列時,我遇到了一個問題。如果我傳遞一個參數,它完美的作品,但是當我有兩個或更多的失敗與folliwng錯誤消息:Bluemix DashDB 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 query node: Error: [IBM][CLI Driver][DB2/LINUXX8664] SQL0420N Invalid character found in a character string argument of the function "DECIMAL". SQLSTATE=22018

我該如何解決這個問題?

+0

這是一個多特別Bluemix一個SQL問題。我添加了SQL標籤,以便更多人能夠看到它。 – ralphearle

+0

我不同意你Ralpherle,因爲一旦我直接在SQL命令行下運行相同的命令,它可以很好地工作,但是在dashdb和node-red下不會發生相同的命令。 –

+0

重要的一點是要儘可能多地關注問題,以獲得良好的答案。具有SQL高級知識的人可能能夠爲您排除故障。還添加了DashDB標籤,但我不確定它是否特定於此服務。 – ralphearle

回答

0

我知道的任何SQL數據庫都會將任何作爲綁定變量值提供的值視爲完全相同的值 - 無需任何解析。

處理可變長度IN列表的常用方法是使用動態SQL,不幸的是,該動態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