2017-01-30 53 views
2

所以我有一個AdoTable連接到數據庫(mdb)和使用它的數據源。此數據源由DBGrid使用...合併列上的AdoDB過濾器

我試圖根據用戶輸入過濾AdoTable。有3個重要的欄目:名稱,姓氏和ID。我想出了這樣的事情作爲一個臨時解決方案:

AdoTable.filter:='surname like ' + 
     QuotedStr('%'+edit1.text+'%')+' or name like ' + 
     QuotedStr('%'+edit1.text+'%')+' or ID like ' + 
     QuotedStr('%'+edit1.text+'%'); 
AdoTable.filtered:=true; 

它的工作,但它不會做什麼我想它做的事...(用於名稱搜索時和surename也不會找到任何東西,因爲它只顯示在一列中)。 所以後來我修改了代碼轉換成這樣:

AdoTable.filter:='surname & " " & name like ' + 
     QuotedStr('%'+edit1.text+'%')+' or name & " " & surname like ' + 
     QuotedStr('%'+edit1.text+'%')+' or ID like ' + 
     QuotedStr('%'+edit1.text+'%'); 
AdoTable.filtered:=true; 

現在,這個會做exacly什麼,我想要它做的,但它會引發異常(EOleException:參數的錯誤類型,超出可接受的範圍內,或彼此衝突)。 這讓我感到驚訝,因爲我認爲它應該像sql命令中的where子句那樣工作(並且它完美地作爲命令)。

我試着用'+'取代'&'。 我可以分割一個輸入文本,但我不想這樣做(如果你有像羅賓范佩西,艾哈邁德ibn漢巴爾等名稱,它會工作很差。)

或者我可以重寫整個程序使用查詢,而不是表,但我不想這樣做(這也意味着我會得到新的記錄集EVERYTIME用戶將更改edit1.text而不是隻是過濾)。

任何想法?

編輯: 這樣命令的作品看起來像這樣

select * from person where surname & " " & name like '%John Smith%' or name & " " & surname like '%John Smith%' or ID like '%John Smith%' 

過濾器看起來像這樣(和它引發的異常)

surname & " " & name like '%John Smith%' or name & " " & surname like '%John Smith%' or ID like '%John Smith%' 

注意,有可能是「HN史密斯」,而不是'約翰史密斯',所以它會發現'卡恩史密瑟斯'等

+0

還有一些未知的部分: 什麼類型是ID?你的代碼假設它是一個聽起來不正確的字符串,大多數ID是一個數字。 第二:你的數據庫是什麼?當你使用例如SQL Express'%'是正確的,當您使用Access時,您必須使用'*' 您能顯示生成的過濾器字符串嗎? –

+0

ID確實是字符串。它可以是'123abc'之類的東西。我在網上發現,Access使用'%'('*'不起作用)。因此,如果我們的過濾器是'姓氏&'「&名稱,如''%John Smith%''或姓名'」&姓氏如''John Smith%''或ID如''John Smith%'''如果我們正在搜索名字和姓氏或'姓氏'「&名稱,如''%0123abcd%''或姓名'」&姓氏如''%0123abcd%''或ID如''%0123abcd%'''正在搜索ID –

+0

請發佈您的解決方案回答 – kobik

回答

1

下面的代碼可以很好地使用AdoTable訪問employee ta在德爾福dbdemos.mdb數據庫。我的AdoConnection使用Microsoft Jet 4.0 OLE DB驅動程序。

procedure TForm1.Button1Click(Sender: TObject); 
var 
    FilterExpr : String; 
begin 
    AdoTable1.Filtered := not AdoTable1.Filtered; 
    if AdoTable1.Filtered then begin 
    FilterExpr := 'FirstName like ' + QuotedStr('%' + Edit1.Text + '%') + ' or LastName like ' + QuotedStr('%' + Edit1.Text + '%'); 
    AdoTable1.Filter := FilterExpr; 
    end; 
end; 

我認爲你的錯誤可能是使用你提到的特定於Access的語法。您通過ADO層訪問表,並且AFAIK需要與您使用的語法相同的語法。爲一個Sql Server後端。

從您的評論,它好像要覆蓋的情況下,用戶類型到您的Edit1.Text第一個名字後面加一個空格,然後一個片段或姓的片段。下面將做到這一點:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    FilterExpr : String; 
    P : Integer; 
    S1, 
    S2 : String; 
begin 
    AdoTable1.Filtered := not AdoTable1.Filtered; 
    if AdoTable1.Filtered then begin 
    P := Pos(' ', Trim(Edit1.Text)); 
    if P > 0 then begin 
     S1 := Copy(Trim(Edit1.Text), 1, P - 1); 
     S2 := Copy(Trim(Edit1.Text), P + 1, MaxInt); 
     FilterExpr := '(FirstName like ' + QuotedStr('%' + S1 + '%') + ')'; 
     FilterExpr := FilterExpr + ' or (LastName like ' + QuotedStr('%' + S2 + '%') + ')'; 
    end 
    else 
     FilterExpr := 'FirstName like ' + QuotedStr('%' + Edit1.Text + '%') + ' or LastName like ' + QuotedStr('%' + Edit1.Text + '%'); 
    AdoTable1.Filter := FilterExpr; 
    end; 
end; 

更新:如果你想允許用戶輸入類似

HN史密斯

那麼你可以使用一個FilterRecord事件是這樣的,而不是上面的代碼。

procedure TForm1.ADOTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean); 
var 
    S : String; 
begin 
    S := LowerCase(DataSet.FieldByName('FirstName').AsString + ' ' + DataSet.FieldByName('LastName').AsString); 
    Accept := Pos(LowerCase(Edit1.Text), S) > 0; 
end; 

顯然,轉換爲LowerCase是忽略用戶可能使用的任何大小寫。

+0

是的,但這會找到姓名或姓氏...對嗎?我得到了這個工作,但我需要兩個:D。無論哪種方式,我感謝你的回答,但我認爲我已經找到了解決方案... –

+0

@RadimNyč:對不起,你是什麼意思「我需要兩個」?如果您的意思是您希望過濾器查找firtname和lastname都包含Edit1.Text中的內容的記錄,只需將過濾器中的「或」更改爲「和」即可。 – MartynA

+0

不......我需要edit1.text像'約翰史密斯'..這會尋找名字'約翰史密斯'和/或姓'約翰史密斯',它不會找到任何東西... –

1

我發現這個:Using LIKE statement for filtering和使用接受的答案,它工作得很好。 (找不到它遲早是問題相當不同)

表濾波器:

procedure TDataModule1.ADOTableFilterRecord(DataSet: TDataSet; 
    var Accept: Boolean); 
var 
    nameSurname :string; 
    surnameName :string; 
begin 
    nameSurname:= DataSet.FieldByName('name').AsString+' '+DataSet.FieldByName('surname').AsString; 
    surnameName:= DataSet.FieldByName('surname').AsString+' '+DataSet.FieldByName('name').AsString; 

    if assigned(MainForm) then 
    Accept := (Pos(MainForm.edit1.Text, nameSurname) > 0) 
    or (Pos(MainForm.edit1.Text, surnameName) > 0) 
    or (Pos(MainForm.edit1.Text, DataSet.FieldByName('ID').AsString) > 0); 
end; 

上編輯變化:

procedure TMainForm.edit1Change(Sender: TObject); 
begin 
    DataModule1.AdoTable.Filtered:=false; 
    if edit1.Text<>'' then 
     DataModule1.AdoTable.Filtered:=True; 
end; 

謝謝你的時間......我會離開它在這裏..我想最終有人可能需要它