全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:8088
推到 Plurk!
推到 Facebook!

SQL語法內含雙引號新增問題

答題得分者是:TWY
lamp
一般會員


發表:3
回覆:10
積分:7
註冊:2006-07-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-11-10 17:54:29 IP:60.249.xxx.xxx 訂閱

測試環境
MSSQL 2000 D5

主要問題是SQL語法內含 " 時要新增至資料庫發生錯誤.
我的寫法在如下.
sSQL:=' insert into test_P '
' (pnumber,pname) '
' values '
' ('
' ''' Edit1.Text ''','
' ''' Edit2.Text ''''
')';

利用ADO新增及ClientDataSet1新增會有不同的結果.
ADO新增 OK,
ClientDataSet1新增會有錯誤產生.
我想請教一下我的寫法是有什麼地方出錯了.
感謝.

PS:附檔含測試程式及TEST TABLE 資料結構


編輯記錄
lamp 重新編輯於 2009-11-18 11:48:45, 註解 無‧
holydisciple
一般會員


發表:3
回覆:24
積分:10
註冊:2009-11-06

發送簡訊給我
#2 引用回覆 回覆 發表時間:2009-11-11 14:14:16 IP:220.128.xxx.xxx 訂閱
你好,

通常我都不直接用 Insert,而是用 DataSet 先讀取零筆進來,如下

ds.close;
ds.CommandText := 'select top 0 * from 資料表名稱';
ds.Open;
ds.Append;
// 填資料
ds.Post;

這樣就不用管那些單引號了,但如果要用 Insert,一定要先 StringReplace,因為內容是使用者輸入的,你不能禁止他不能輸入單引號,例如

var s1, s2 : string;
s1 := StringReplace(Edit1.Text, '''', '', [rfReplaceAll]);
s2 := StringReplace(Edit2.Text, '''', '', [rfReplaceAll]);
sSQL := Format('insert into test_P (pnumger, pname) values(''%s'', ''%s'')', [s1, s2]); // 用 Format() 才不會打那麼多單引號

------
有沒有可能,上帝使用程式操作世界?
lamp
一般會員


發表:3
回覆:10
積分:7
註冊:2006-07-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-11-11 16:07:22 IP:60.249.xxx.xxx 訂閱

===================引 用 holydisciple 文 章===================
你好,

通常我都不直接用 Insert,而是用 DataSet 先讀取零筆進來,如下

ds.close;
ds.CommandText := 'select top 0 *from 資料表名稱';
ds.Open;
ds.Append;
// 填資料
ds.Post;

這樣就不用管那些單引號了,但如果要用 Insert,一定要先 StringReplace,因為內容是使用者輸入的,你不能禁止他不能輸入單引號,例如

var s1, s2 : string;
s1 := StringReplace(Edit1.Text, '''', '', [rfReplaceAll]);
s2 := StringReplace(Edit2.Text, '''', '', [rfReplaceAll]);
sSQL := Format('insert into test_P (pnumger, pname) values(''%s'', ''%s'')', [s1, s2]); // 用 Format() 才不會打那麼多單引號


感謝您的回覆...
1.大大所提供的方法是第一種方案是可以解決沒錯,但是因為要維護舊系統修改幅度過大,可能無法依法執行.

2.小弟目前的問題是輸入雙引號 < " >的問題並不是單引號的問題.舉例來說以下這段SQL語法,利用TADOQuery元件來新增不會有任何錯誤產,但是利用TClientDataSet 郤會產生錯誤無法新增.
insert into test_P (pnumber,pname) values ( 'P0004', '鋼管 1"')

PS:我提供的測試檔有簡單的程式,有興趣的朋友可以試試看.

TWY
高階會員


發表:2
回覆:133
積分:152
註冊:2009-09-02

發送簡訊給我
#4 引用回覆 回覆 發表時間:2009-11-14 23:35:55 IP:220.132.xxx.xxx 訂閱
你好。試著用 QuotedStr() 包起參數,應該可以解決你的問題。(說明請按F1)

lamp
一般會員


發表:3
回覆:10
積分:7
註冊:2006-07-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2009-11-16 17:16:36 IP:60.249.xxx.xxx 訂閱

===================引 用 TWY 文 章===================
你好。試著用QuotedStr() 包起參數,應該可以解決你的問題。(說明請按F1)


感謝您的回覆...測試結果TClientDataSet還是不行.
原本的sql語法如下
sSQL = insert into test_P (pnumber,pname) values ( 'P0006', '鋼管 1"' )
加入QuotedStr() ,
sSQL:=QuotedStr(sSQL)

sSQL= ' insert into test_P (pnumber,pname) values ( ''P0006'', ''鋼管 1"'' )'

執行結果還是產生錯誤.

利用 TADOQuery 加入QuotedStr()

原本的sql語法如下
sSQL = insert into test_P (pnumber,pname) values ( 'P0006', '鋼管 1"' )
加入QuotedStr() ,
sSQL:=QuotedStr(sSQL)

sSQL= ' insert into test_P (pnumber,pname) values ( ''P0006'', ''鋼管 1"'' )'
執行完,可以順利新增.
以TADOQuery來看,不管是insert into test_P (pnumber,pname) values ( 'P0006', '鋼管 1"' ) 或 ' insert into test_P (pnumber,pname) values ( ''P0006'', ''鋼管 1"'' )' , 該元件執行時都能順利解析SQL語法.

是不是 ClientDataSet 還有一些參數可以調整,還是BDE的問題?
ko
資深會員


發表:28
回覆:785
積分:444
註冊:2002-08-14

發送簡訊給我
#6 引用回覆 回覆 發表時間:2009-11-17 14:05:46 IP:61.66.xxx.xxx 訂閱
請問
insert into test_P (pnumber,pname) values ( 'P0006', '鋼管 1"' )
這一句您測試過在 Analyzer 中執行過嘛?
還有QuotedStr() 的意思是..包在EDIT1...
sSQL:=' insert into test_P '
' (pnumber,pname) '
' values '
' ('
' QuotedStr(Edit1.Text) ','
' 'QuotedStr(Edit2.Text) QuotedStr('"')
')';

------
======================
昏睡~
不昏睡~
不由昏睡~
編輯記錄
ko 重新編輯於 2009-11-17 14:09:50, 註解 無‧
TWY
高階會員


發表:2
回覆:133
積分:152
註冊:2009-09-02

發送簡訊給我
#7 引用回覆 回覆 發表時間:2009-11-17 17:47:00 IP:211.21.xxx.xxx 訂閱
 抱歉先前給了錯誤方向,QuotedStr一般用來解決內容有單引號的問題,雙引號對在Delphi的SQL來說不具有破壞力(不會有問題)。
也謝謝 ko 兄幫忙舉例了 QuotedStr 的用法(只需要包起參數/變數,不是把整個 SQL 字串包起來喔)

我下載了你的範例也建立起 test_p 來測試,我敢說你的問題不是 SQL 語法問題,我有用你的範例新增過了...
因為我沒有另外在寫個 AP Server,所以直接在你傳上的程式拉個 TDabase TQuery TDataSetProvider 元件來連結資料庫(跟實際連結AP Server意思一樣),沒有改你的任何程式按下 Button1 (OnClick) => 新增成功!
其中屬性比較特別的就是 TDataSetProvider.Options.poAllowCommandText 必須設定 True ,這樣才能讓 TClientDataSet 自己傳上 SQL 來執行,我猜你應該是這裡沒設吧!?(或其他 NTier 連結上的問題,因為你忘了把錯誤訊息 Post 出來,所以僅能做此猜測)


lamp
一般會員


發表:3
回覆:10
積分:7
註冊:2006-07-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2009-11-18 12:02:10 IP:60.249.xxx.xxx 訂閱
===================引 用 TWY 文 章===================
抱歉先前給了錯誤方向,QuotedStr一般用來解決內容有單引號的問題,雙引號對在Delphi的SQL來說不具有破壞力(不會有問題)。
也謝謝 ko 兄幫忙舉例了 QuotedStr 的用法(只需要包起參數/變數,不是把整個 SQL 字串包起來喔)

我下載了你的範例也建立起 test_p 來測試,我敢說你的問題不是 SQL 語法問題,我有用你的範例新增過了...
因為我沒有另外在寫個 AP Server,所以直接在你傳上的程式拉個 TDabase TQuery TDataSetProvider 元件來連結資料庫(跟實際連結AP Server意思一樣),沒有改你的任何程式按下 Button1 (OnClick) => 新增成功!
其中屬性比較特別的就是 TDataSetProvider.Options.poAllowCommandText 必須設定 True ,這樣才能讓 TClientDataSet 自己傳上 SQL 來執行,我猜你應該是這裡沒設吧!?(或其他 NTier 連結上的問題,因為你忘了把錯誤訊息 Post 出來,所以僅能做此猜測)


=======

感謝,ko兄及TWY大大的回覆.
抱歉,誠如TWY大大所言,我的測試程式有點問題並不是SQL 語法問題,

sSQL = insert into test_P (pnumber,pname) values ( 'P0006', '鋼管 1"' ) ,確定是可以新增的.
我的測試程式無法新增是因為我只設ClientDataSet1我只設定了RemoteServer,忘了設定ProviderName.
造成了資料無法新增.


我的測試程式稍為改了一下,我將我無法順利新增的sql語法我重po如下.
insert into REQUIRE ( RENUMBER,SERIAL,PNUMBER,PNAME, LISTPRICE,QUODISCOUNT,QUODISPRICE,AMOUNT,
LTCOST,EQUCOST,REMARK,CTDT,CTRU,CHECKED, SWTYPE,SWNUMBER ) VALUES ('200911170002','1','IPF6445110','SGP6445
白碳鋼鋼管 6.1M 1"','394','100','394','3','1182','393.979',' ','2009/11/17 16:56','0001','0','','')


以上語法,我利用Analyzer執行時可以順利新增資料.但是我利用我的測試程式去執行時會發生 Missing right quote 的錯誤訊息.

麻煩那位大大有空幫我看一下我的語法是那出錯了.感謝!

PS:測試檔已更新,麻煩重新下庫內含 CREATE REQUIRE table 的語法.
TWY
高階會員


發表:2
回覆:133
積分:152
註冊:2009-09-02

發送簡訊給我
#9 引用回覆 回覆 發表時間:2009-11-18 18:22:29 IP:211.21.xxx.xxx 訂閱
 我剛玩了很久,這的確是個有趣的現象,我在想...是否為元件的 Bug 呢!? 
(雖然我盡可能要求自己不要把不能說明或理解的現象歸納為元件Bug,不過這個現象倒真的超出我的認知了)

我把重現的規則簡單描述出來,讓有能力的高手來試玩、或給大家解惑一下~
建立一個簡單 Table 只要三個欄位,假設 FInt,FString,FDateTime
若 SQL 為 insert into ATable(FString,FDateTime) values('A"','2009-11-11 12:34:56')
若用 TQuery 直接寫入會得到 "Missing right quote." 的錯誤。若使用 TADOQuery 寫入會得到 "提供不一致或不完全的資訊導致參數物件不適當地被拒。" 的錯誤。用 SQL Monitor 檢視會發現 SQL 變成 insert into REQUIRE ( PNAME,ctdt) VALUES ('A"','2009-11-11 12?
但直接用 SQL Query Analyzer 新增是 OK的。

另外,若語法把"字串"、"日期"欄位隔開,就不會有錯誤,例如 insert into ATable(FString,FInt,FDateTime) values('A"',1,'2009-11-11 12:34:56')
目前看來 SQL 語法字串緊跟著日期欄位時,會把字串內容中的雙引號也當作單引號處理。
這還真的很奇怪哩~

ps: 1.此問題與 NTier or ClientDataSet 無關,直接拉個 DataBase & Query 就可以模擬
2. 我是用 Memo 來輸入 SQL,非寫在 Code 裡,再以 Query.SQL.Text := Memo1.Lines.Text; 方式讀入執行


編輯記錄
TWY 重新編輯於 2009-11-19 11:39:37, 註解 無‧
jackiemi2_seed
中階會員


發表:37
回覆:97
積分:76
註冊:2006-09-11

發送簡訊給我
#10 引用回覆 回覆 發表時間:2009-11-19 14:52:17 IP:61.218.xxx.xxx 訂閱
我的筆記,QuotedStr是這樣用的,我是用adocom去執行,
clientdataset下sql不會用,參考看看

s:='update test1 ';
s:=s 'set ' format('t2=%s',[QuotedStr(edit1.Text)] ) ' ';
s:=s 'where t1=''001'' ';
adocom.CommandText:=s;
------
OS : Win 7 pro
Program : Delphi 7
DataBase : Ms Sql 2008
TWY
高階會員


發表:2
回覆:133
積分:152
註冊:2009-09-02

發送簡訊給我
#11 引用回覆 回覆 發表時間:2009-11-19 15:57:34 IP:211.21.xxx.xxx 訂閱
我想這個問題(現象)已經不是 QuotedStr 能解決的,也與 BDE or ADO,Client-Server or NTier 沒有直接關係了。
有興趣的話,可參照我上面描述簡單方法 try 一下喔~

===================引 用 jackiemi2_seed 文 章===================
我的筆記,QuotedStr是這樣用的,我是用adocom去執行,
clientdataset下sql不會用,參考看看

s:='update test1 ';
s:=s 'set ' format('t2=%s',[QuotedStr(edit1.Text)] ) ' ';
s:=s 'where t1=''001'' ';
adocom.CommandText:=s;
jackiemi2_seed
中階會員


發表:37
回覆:97
積分:76
註冊:2006-09-11

發送簡訊給我
#12 引用回覆 回覆 發表時間:2009-11-20 08:39:33 IP:61.218.xxx.xxx 訂閱
感覺問題出在,文字有雙引號和datetime同時出現
改用Parameters的方式就可以了,參考看看
ClientDataSet1不知是否有Parameters可以用
s:='insert into ATable(FString,FInt,FDateTime) values(:FString,:FInt,:FDateTime)';
adocom.CommandText:=s;
adocom.Parameters.ParamValues['FString']:='A"';
adocom.Parameters.ParamValues['FInt']:=2;
adocom.Parameters.ParamValues['FDateTime']:='2009-01-01 1:22:33';
adocom.Execute;
但Parameters在輸入中文字時,好像很容易出問題
------
OS : Win 7 pro
Program : Delphi 7
DataBase : Ms Sql 2008
TWY
高階會員


發表:2
回覆:133
積分:152
註冊:2009-09-02

發送簡訊給我
#13 引用回覆 回覆 發表時間:2009-11-22 00:08:28 IP:220.132.xxx.xxx 訂閱
 我剛用了一樣的模擬方法(參考上面描述)做了些實驗,這次資料庫換成Oracle 9i,結果如下...
1. BDE 仍然有同樣問題 2. RemObject Data Abstract 套件 OK 3. Oracle Access(ODAC) 套件 OK
(後面兩個都是第三方元件)

網路搜尋一下,也有人反應一樣的問題,也有很多解決方法建議 (例如用 StringReplace 等),但就是沒有看到有人對此現象做出原因說明。
目前線索看來,似乎指向這是 Delphi 內部元件的 Bug,除此之外我尚不知道能如何解釋了...


編輯記錄
TWY 重新編輯於 2009-11-22 00:18:11, 註解 無‧
lamp
一般會員


發表:3
回覆:10
積分:7
註冊:2006-07-13

發送簡訊給我
#14 引用回覆 回覆 發表時間:2009-11-30 11:32:21 IP:60.249.xxx.xxx 訂閱
感謝各位大大的回覆,尤其是TWY大大不辭辛勞的測試.發現不是SQL語法的問題,而是日期欄位出了狀況.
問題我已解決,直接利用SQL函數代入該欄位,確定可以新增.
以下是我的解決方法.大家以後再遇到類似問題可以試.SQL函數各家資料庫略有不同,請自行調整.
原SQL語法:
insert into REQUIRE ( RENUMBER,SERIAL,PNUMBER,PNAME, LISTPRICE,QUODISCOUNT,QUODISPRICE,AMOUNT,
LTCOST,EQUCOST,REMARK,CTDT,CTRU,CHECKED, SWTYPE,SWNUMBER ) VALUES ('200911170002','1','IPF6445110','SGP6445
白碳鋼鋼管 6.1M 1"','394','100','394','3','1182','393.979',' ', '2009/11/17 16:56','0001','0','','')

新SQL語法:
insert into REQUIRE ( RENUMBER,SERIAL,PNUMBER,PNAME, LISTPRICE,QUODISCOUNT,QUODISPRICE,AMOUNT,
LTCOST,EQUCOST,REMARK,CTDT,CTRU,CHECKED, SWTYPE,SWNUMBER ) VALUES ('200911170002','1','IPF6445110','SGP6445
白碳鋼鋼管 6.1M 1"','394','100','394','3','1182','393.979',' ', convert(varchar(16),getdate(),120),'0001','0','','')

編輯記錄
lamp 重新編輯於 2009-11-30 11:35:35, 註解 無‧
系統時間:2024-04-26 7:52:22
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!