我在 dbgrid 中選擇了一些行,然后必須在存盤程序或查詢的引數中傳遞一組值。我使用 Firebird 3。如果未預定義值的數量,如何在單個引數中傳遞多個值?例如,對于 good_id 的 3 個值,我得到錯誤:
字串“7802 ,8403 ,11461”的轉換錯誤
create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
begin
for select good_id, good from goods where good_id in (:id)
into :good_id, :good
do suspend;
end
procedure Button1Click(Sender: TObject);
var
str : String;
i : Integer;
begin
Query1.Close;
Query1.SQL.Text := 'select * from sp_goods(:id) ';
with DBGridGoods do
begin
if SelectedRows.Count > 0 then
begin
str := '';
With DataSource.DataSet do
for i := 0 to SelectedRows.Count - 1 do
begin
GotoBookmark(SelectedRows.Items[i]) ;
str := str FieldByName('good_id').asString ', ';
end;
str := copy( str, 1, length( str ) - 2 );
end;
end;
Query1.Params[0].AsString:=str;
Query1.Open;
結尾;
如果我在 IBExpert 中呼叫存盤程序
select * from sp_goods('8403')
它有效,但是
select * from sp_goods('8403','7802')
回傳錯誤
程序 sp_goods 的輸入引數不匹配。
如果我使用查詢而不是存盤程序,則會發生同樣的錯誤。
我嘗試使用陣列作為值,但得到空資料集:
procedure Button1Click(Sender: TObject);
var
a: array of integer;
begin
Query1.Close;
Query1.SQL.Text := 'select * from sp_goods(:id) ';
setlength(a, 2);
a[0]:= 7802;
a[1]:=8403;
Query1.Params[0].Value:= a;
Query1.Open;
end;
uj5u.com熱心網友回復:
沒有辦法將一組值傳遞給 Firebird 中的單個引數。
在您的示例中,整個存盤程序是沒有意義的,使用連接一次將所有值選擇到原始網格中更簡單、更快捷。如果您希望僅獲取選定專案的商品并將它們放入單獨的網格中,最好的方法是在回圈中執行查詢,而不是收集 id 串列。如果您準備一次查詢(在回圈內執行 prepare() 呼叫是一個常見錯誤),它將非常快。
uj5u.com熱心網友回復:
過去,我通過兩種方式實作了這一目標。一種是使用Dynamic Queries,這不是您想要做的,除非沒有其他選擇。
另一種方法是使用此程序。 我正在從我的檔案中拖出這個,還有其他方法可以更有效地實作這一目標。我提供它是為了展示如何做到這一點。
create or alter procedure "Split_Line"
( IP_NOTE VARCHAR (16000),
IP_SEP CHAR (1))
returns (
"Index" INTEGER,
"Line" VARCHAR (16000))
as
declare variable lLines varchar (16000);
declare variable lMax integer;
declare variable lPos integer;
begin
lMax = 16000;
lLines = ip_Note;
"Index" = 0;
while (lLines is not null)
do begin
"Line" = null;
lPos = null;
select "Result" from "Pos" (:Ip_Sep, :lLines) into :lPos;
if (lPos is null or lPos = 0)
then begin
/* Last line with no separator */
"Line" = lLines;
lLines = null;
end
else if (lPos = 1 and lLines = Ip_Sep)
then begin
/* Last char is a separator */
"Line" = '';
lLines = null;
end
else begin
/* Normal Case */
// "Line" = "SubStr" (:lLines, 1, :lPos-1);
// lLines = "SubStr" (:lLines, :lPos 1, :lMax);
"Line" = substring (:lLines from 1 for :lPos-1);
lLines = substring (:lLines from :lPos 1 for :lMax);
end
"Index" = "Index" 1;
suspend;
end
end
您可以使用字串中的逗號分隔值和分隔符(在本例中為逗號)呼叫它。它會回傳一個您使用的表。
使用示例
select * from "Split_Line" ('x,a,cat', ',')
將回傳
| 指數 | 線 |
|---|---|
| 1 | X |
| 2 | 一個 |
| 3 | 貓 |
你可以在你的情況下使用它
create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
begin
for select good_id, good from goods
where good_id in (select cast("Line" as numeric (18, 0))
from "Split_Line" (:id, ','))
into :good_id, :good
do suspend;
end
支持Split_String之前編譯的程式
create or alter procedure "Pos"
( SUBSTR VARCHAR (100),
STR VARCHAR (16000))
returns ( "Result" INTEGER)
as
DECLARE VARIABLE SubStr2 VARCHAR(16256); /* 1 SubStr-lenght Str-length */
DECLARE VARIABLE Tmp VARCHAR(255);
BEGIN
IF (SubStr IS NULL OR Str IS NULL)
THEN BEGIN
"Result" = NULL;
suspend;
EXIT;
END
IF (SubStr = '' OR Str = '')
THEN BEGIN
"Result" = 0;
suspend;
EXIT;
END
SubStr2 = SubStr || '%';
Tmp = '';
"Result" = 1;
WHILE (Str NOT LIKE SubStr2 AND Str NOT LIKE Tmp)
DO BEGIN
SubStr2 = '_' || SubStr2;
Tmp = Tmp || '_';
"Result" = "Result" 1;
END
IF (Str LIKE Tmp)
THEN "Result" = 0;
suspend;
END
我已經替換了我的substr(來自我的用戶定義函式庫)以在Split_Line程序中使用 firebird子字串。
為參考的識別符號道歉,請始終使用Dialect 3。奇怪的大寫是支持當時只能使用大寫程式的 Crystal Reports。
uj5u.com熱心網友回復:
另一種方法是使用Dynamic Queries。
create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
declare lsql varchar (5000);
begin
lsql = 'select good_id, good from goods where good_id in (' || :id || ')';
for execute statement lsql
into :good_id, :good
do suspend;
end
缺點
- 通常,在編譯程序時,會同時準備查詢。因此,執行速度更快。使用Dynamic Queries或Dynamic Sql,每次執行程序時都必須準備查詢。
- 通常,在編譯程序時,引擎會驗證表和欄位等。在這種情況下,驗證發生在執行時。因此,您必須非常小心如何構建查詢。
注意- 我沒有時間用一個真實的表來測驗它,但它可以編譯。(現在是凌晨 3 點,所以我明天可能會檢查)。我通常不會推薦這個,但一切都有一席之地。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/516716.html
標籤:德尔福火鸟
