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

以型態為nvarchar的欄位為條件無法查出想要資料

答題得分者是:aftcast
hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-03-31 18:10:23 IP:220.136.xxx.xxx 訂閱
 使用MS SQL 2000

Staff 有個欄位為StaffName nvarchar(20)

用ADOQuery 來查詢資料時
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add(' Select * from Staff where StaffName=:Staffname ');
ADOQuery1.Parameters.ParamByName('StaffName').DataType:=ftWideString;
//edStaffName:TTntEdit;
ADOQuery1.Parameters.ParamByName('StaffName').Value:=edStaffName.Text;
ADOQuery1.Open;
這樣的式子無法查出所要的資料,只要edStaffName中的資料有用到Unicode的字,Select 就會沒有資料。

請教該如何解決,謝謝!
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-03-31 21:36:06 IP:220.135.xxx.xxx 訂閱
StaffName=N:Staffname

===================引 用 hungyulin 文 章===================
使用MS SQL 2000

Staff 有個欄位為StaffName nvarchar(20)

用ADOQuery 來查詢資料時
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add(' Select * from Staff where StaffName=:Staffname ');
ADOQuery1.Parameters.ParamByName('StaffName').DataType:=ftWideString;
//edStaffName:TTntEdit;
ADOQuery1.Parameters.ParamByName('StaffName').Value:=edStaffName.Text;
ADOQuery1.Open;
這樣的式子無法查出所要的資料,只要edStaffName中的資料有用到Unicode的字,Select 就會沒有資料。

請教該如何解決,謝謝!
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-04-01 13:21:49 IP:220.136.xxx.xxx 訂閱

===================引 用 aftcast 文 章===================
StaffName=N:Staffname

===================引 用 hungyulin 文 章===================
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add(' Select * from Staff where StaffName=N:Staffname ');
ADOQuery1.Parameters.ParamByName('StaffName').DataType:=ftWideString;
//edStaffName:TTntEdit;
ADOQuery1.Parameters.ParamByName('StaffName').Value:=edStaffName.Text;
ADOQuery1.Open;
這樣的會出現錯誤 raised exceptino class EOldException with message '無效的資料行名稱N@P1。
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2011-04-01 13:30:56 IP:210.64.xxx.xxx 訂閱
OK, 抱歉我很久沒用delphi,而且我也不用TADOQuery,而是用TADODataSet或是TADOCommand。但我很確定你的關鍵問題在 N 這個字元。

我換個方式來回好了,但你自己稍變化一下。

sql2000裡要select一個含nchar型別的語法應該是要這樣

Select * from Staff where StaffName=N'Aftcast' ;

我不知道用"取代"的方式該如何,但我通常是用字串相加,只要加成上面那樣的形式,那整個就會是對的。


------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#5 引用回覆 回覆 發表時間:2011-04-01 14:16:08 IP:220.136.xxx.xxx 訂閱

===================引 用 aftcast 文 章===================
Select * from Staff where StaffName=N'Aftcast' ;
===================引 用 aftcast 文 章===================
對,我知道在SQL工具中這樣下語法是可以,就是不知道在Delphi中要怎麼作??


pedro
尊榮會員


發表:152
回覆:1187
積分:892
註冊:2002-06-12

發送簡訊給我
#6 引用回覆 回覆 發表時間:2011-04-01 15:02:26 IP:60.248.xxx.xxx 未訂閱
Hi

不好意思,我來插花一下

[code delphi]
With AdoQuery1 do
begin
Sql.Clear;
Sql.Add('Select * from Staff ');
Sql.Add('where StaffName=N' QuotedStr('Aftcast'));
end;
[/code]

===================引 用 aftcast 文 章===================
Select * from Staff where StaffName=N'Aftcast' ;
===================引 用aftcast文 章===================
對,我知道在SQL工具中這樣下語法是可以,就是不知道在Delphi中要怎麼作??


hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2011-04-01 16:12:01 IP:220.136.xxx.xxx 訂閱

===================引 用 pedro 文 章===================
Hi

不好意思,我來插花一下

[code delphi]
With AdoQuery1 do
begin
Sql.Clear;
Sql.Add('Select * from Staff ');
Sql.Add('where StaffName=N' QuotedStr('Aftcast'));
end;
[/code]
===================引 用 pedro 文 章===================
Sql.Add('where StaffName=N' QuotedStr('綉'));
pedro
尊榮會員


發表:152
回覆:1187
積分:892
註冊:2002-06-12

發送簡訊給我
#8 引用回覆 回覆 發表時間:2011-04-01 16:41:13 IP:60.248.xxx.xxx 未訂閱
您Delphi是什麼版本?

試試Sql.Add('where StaffName like N''¯tcast%''),不要使用QuotedStr看看

===================引 用 hungyulin 文 章===================
Sql.Add('where StaffName=N' QuotedStr('綉'));
hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#9 引用回覆 回覆 發表時間:2011-04-01 18:00:52 IP:220.136.xxx.xxx 訂閱

===================引 用 pedro 文 章===================
您Delphi是什麼版本?

試試Sql.Add('where StaffName like N''¯tcast%''),不要使用QuotedStr看看

===================引 用 hungyulin 文 章===================
我是Delphi 5,因為需求不可使用Like一定要絕對值才行。
//edStaffName:TtntEdit;
SQL.Add(' Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff '
' where StaffName=N''' edStaffname.Text ''' ');
用這樣也是不行。
pedro
尊榮會員


發表:152
回覆:1187
積分:892
註冊:2002-06-12

發送簡訊給我
#10 引用回覆 回覆 發表時間:2011-04-01 18:28:50 IP:60.248.xxx.xxx 未訂閱

問題是出在"綉、堃"這些字,經Delphi 5的TEdit是輸入不進去的,
而且一些含有Unicode的字元,也無法以TDBEdit顯示出來

加掛TNTWare Delphi Unicode Components
或裝Unicode補完計劃不知道有沒有幫助?

或許其他前輩有處理過這類問題,看看有沒有其它解法?

===================引 用 hungyulin 文 章===================
我是Delphi 5,因為需求不可使用Like一定要絕對值才行。
//edStaffName:TtntEdit;
SQL.Add(' Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff '
' where StaffName=N''' edStaffname.Text ''' ');
用這樣也是不行。
編輯記錄
pedro 重新編輯於 2011-04-01 04:29:19, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#11 引用回覆 回覆 發表時間:2011-04-01 22:28:48 IP:220.135.xxx.xxx 訂閱
謝謝petro幫忙,我再接手回來。

我一直使用ado tnt 元件,一直沒問題。唯一有差的是我用的是bcb,但我想只是語法上的不同吧?

1/ 請不要用 adoquery 這個元件,極強烈的建議不要用! 因為 微軟ado元件本來只有 adodataset,adocommand,adoconnection這三個。這個adoquery是borland自己把adodataset再進一步包的。

2/ tadoquery裡的sql這個屬性,它是TStrings,並不是WideString(即unicode)。所以
SQL.Add(' Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff '
' where StaffName=N''' edStaffname.Text ''' ');
也一定死!


我剛找到我2003年時寫的delphi程式加以修改… 參考一下吧


[code delphi]
self.ADODataSet2.CommandText := 'Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff where StaffName=N''' edStaffname.Text '''';
self.ADODataSet2.Open;

while not self.ADODataSet2.Eof do begin
edUnicode.Text = VarToWideStr(ADODataSet2['
StaffName']); {自己加一個tnt的元件名叫edUnicode,這是為了讓你知道取法}
label1.Caption = VarToStr(ADODataSet2['Addr1']); {自己加一個Label元件,用以告知你若不是unicode時是這樣取的}
self.ADODataSet2.Next;

[/code]




------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2011-04-01 08:30:11, 註解 無‧
hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#12 引用回覆 回覆 發表時間:2011-04-06 10:28:53 IP:220.136.xxx.xxx 訂閱

===================引 用 aftcast 文 章===================
[code delphi]
{進不了迴圈,因為recordCount為0}
edUnicode.Text = VarToWideStr(ADODataSet2['StaffName']); {自己加一個tnt的元件名叫edUnicode,這是為了讓你知道取法}
label1.Caption = VarToStr(ADODataSet2['Addr1']); {自己加一個Label元件,用以告知你若不是unicode時是這樣取的}
self.ADODataSet2.Next;

[/code]
=====================================================
感謝Aftcast大大的幫忙,如上面所示在self.ADODataSet2.Open後還是進不了下面的迴圈,因為加入了那個where條件導致Select 後的RecordCount為0吧?
後來小弟只好用一個很笨的方法來作,把where條件拿掉,全部Select出來一筆一筆慢慢比對,目前資料不多還可以接受.
[code delphi]
self.ADODataSet2.CommandText := 'Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff'
self.ADODataSet2.Open;

while not self.ADODataSet2.Eof do
begin
if ADODataSet2['StaffName']=edStaffName.Text then
begin
edUnicode.Text = VarToWideStr(ADODataSet2['StaffName']); {自己加一個tnt的元件名叫edUnicode,這是為了讓你知道取法}
label1.Caption = VarToStr(ADODataSet2['Addr1']); {自己加一個Label元件,用以告知你若不是unicode時是這樣取的}
Break;
end;
self.ADODataSet2.Next;
end

[/code]

編輯記錄
hungyulin 重新編輯於 2011-04-05 20:30:24, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#13 引用回覆 回覆 發表時間:2011-04-06 10:54:34 IP:210.64.xxx.xxx 訂閱
請改成如下再測看看? (語法若有錯請自改,我不熟,也沒太多時間去確認 :p ,會分成這麼多段是有原因的,所以請先照著做看看)


[code delphi]
command : WideString;
tail : WideString;
command := 'Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff where StaffName=N''';
command := command edStaffname.Text; {edStaffname是tnt元件喔!}
tail = '''';
command := command tail;
self.ADODataSet2.CommandText := command;

[/code]


------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2011-04-05 20:55:37, 註解 無‧
hungyulin
一般會員


發表:36
回覆:33
積分:13
註冊:2003-10-15

發送簡訊給我
#14 引用回覆 回覆 發表時間:2011-04-06 14:08:11 IP:220.136.xxx.xxx 訂閱
感謝Aftcast大大的幫忙,後來發現在ADODataSet上有一個Propertie叫作ParamCheck要設為False就可以了。

cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#15 引用回覆 回覆 發表時間:2011-04-22 22:50:21 IP:210.202.xxx.xxx 未訂閱
何必那麼麻煩?一行搞定。
ADOQuery1.Sql.Text := Format('Select * from Staff where StaffName=''%s''', [edStaffName.Text]);
我用 Delphi 2006,大量使用 TAdoDateSet 和 TAdoQuery,全部都用 Format() 來組出 Sql 指令,從來都沒有問題。
我的同事都喜歡用 Parameter,我卻不用,無他,一行能搞定,為什麼要多寫幾行?
我同事喜歡先設定一個 TAdoQuery 的 Sql 指令含參數,使用者傳入參數打開,看起來方便,但有兩個缺點。
1.這個 AdoQuery 不能拿來填其他 Sql 指令。
2.在看程式碼的時候,不知道這個 AdoQuery 是幹嘛的,因為指令不在原始碼裡面,每次看到一半都要到物件檢視器看一下才知道,程式碼分離導致程式難閱讀。
==================================
ADOQuery1.SQL.Add(' Select * from Staff where StaffName=:Staffname ');
ADOQuery1.Parameters.ParamByName('StaffName').DataType:=ftWideString;
//edStaffName:TTntEdit;
ADOQuery1.Parameters.ParamByName('StaffName').Value:=edStaffName.Text;
===================引 用 hungyulin 文 章===================
感謝Aftcast大大的幫忙,後來發現在ADODataSet上有一個Propertie叫作ParamCheck要設為False就可以了。

aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#16 引用回覆 回覆 發表時間:2011-04-22 23:02:31 IP:122.126.xxx.xxx 訂閱
Cancer 你好,

你的寫法很好,也很棒。只是唯一要注意的是… 當命令中有unicode時,千萬不要用 tadoquery !!! ,因為 微軟ado元件本來只有 adodataset,adocommand,adoconnection這三個。這個adoquery是borland自己把adodataset再進一步包的。ms 的那三個都是unicode的

2/ TStrings,並不是WideString(即unicode)。所以
SQL.Add(' Select Area,GroupName,StaffName,MobilPhone,Phone1,Addr1 from Staff ' ' where StaffName=N''' edStaffname.Text ''' ');



===================引 用 cancer 文 章===================
何必那麼麻煩?一行搞定。
ADOQuery1.Sql.Text := Format('Select * from Staff where StaffName=''%s''', [edStaffName.Text]);
我用 Delphi 2006,大量使用 TAdoDateSet 和 TAdoQuery,全部都用 Format() 來組出 Sql 指令,從來都沒有問題。
我的同事都喜歡用 Parameter,我卻不用,無他,一行能搞定,為什麼要多寫幾行?
我同事喜歡先設定一個 TAdoQuery 的 Sql 指令含參數,使用者傳入參數打開,看起來方便,但有兩個缺點。
1.這個 AdoQuery 不能拿來填其他 Sql 指令。
2.在看程式碼的時候,不知道這個 AdoQuery 是幹嘛的,因為指令不在原始碼裡面,每次看到一半都要到物件檢視器看一下才知道,程式碼分離導致程式難閱讀。
==================================
ADOQuery1.SQL.Add(' Select * from Staff where StaffName=:Staffname ');
ADOQuery1.Parameters.ParamByName('StaffName').DataType:=ftWideString;
//edStaffName:TTntEdit;
ADOQuery1.Parameters.ParamByName('StaffName').Value:=edStaffName.Text;
===================引 用 hungyulin 文 章===================
感謝Aftcast大大的幫忙,後來發現在ADODataSet上有一個Propertie叫作ParamCheck要設為False就可以了。

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
sryang
尊榮會員


發表:39
回覆:762
積分:920
註冊:2002-06-27

發送簡訊給我
#17 引用回覆 回覆 發表時間:2011-04-23 00:47:36 IP:114.35.xxx.xxx 訂閱
Cancer 網友,請修改你的寫法,改成跟你同事一樣使用參數
不然哪天 SQL Injection 就找上你
如果我在 edStaffName 中輸入 「'; drop table Staff; --」一查詢你的 Staff 資料表馬上不見
假如你預先料想到這樣的狀況,而使用沒有權限刪除資料表的使用者登入資料庫
我輸入「'; update Staff set StaffName=''; --」一查詢你的 StaffName 也會全部變成空白

防止 SQL Injection 最重要,也最有效的,就是使用參數化查詢

===================引 用 cancer 文 章===================
何必那麼麻煩?一行搞定。
ADOQuery1.Sql.Text := Format('Select * from Staff where StaffName=''%s''', [edStaffName.Text]);
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
編輯記錄
sryang 重新編輯於 2011-04-22 10:56:23, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#18 引用回覆 回覆 發表時間:2011-04-23 02:50:06 IP:122.126.xxx.xxx 訂閱
經sryang提起了 sql injection的情形後 (好久沒去想這個問題,一般是網頁才會考量,yang想好多:p),我進一步去了解 ADodataset 裡關於TParameters的部份。發現…

TAdoQuery裡的sql是不行的)

TAdoQuery裡的sql是不行的)

追一下輸出,發現大概是送出這樣的指令至 mssql

exec sp_executesql N'select * from Customers where CustomerID = @P1', N'@P1 sql_variant', N'AROUT'

至此有完美的解法了。yeah!

謝謝sryang常常會引發我更深入去回憶、去想… :-)

===================引 用 sryang 文 章===================
Cancer 網友,請修改你的寫法,改成跟你同事一樣使用參數
不然哪天 SQL Injection 就找上你
如果我在 edStaffName 中輸入 「'; drop table Staff; --」一查詢你的 Staff 資料表馬上不見
假如你預先料想到這樣的狀況,而使用沒有權限刪除資料表的使用者登入資料庫
我輸入「'; update Staff set StaffName=''; --」一查詢你的 StaffName 也會全部變成空白

防止 SQL Injection 最重要,也最有效的,就是使用參數化查詢

===================引 用 cancer 文 章===================
何必那麼麻煩?一行搞定。
ADOQuery1.Sql.Text := Format('Select * from Staff where StaffName=''%s''', [edStaffName.Text]);
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
系統時間:2024-11-25 19:42:47
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!