如何从 PostgreSQL 存储过程中获取结果集?
How to get result set from PostgreSQL stored procedure?
我在 PostgreSQL 11 中创建了一个存储过程来执行 CRUD 操作,它适用于 1. 创建 2. 更新 3. 删除,但是当我 运行 通过传递 Condition = 4
读取命令时select 个结果集,出现以下错误。
我已经使用 PostgreSQL 函数获取结果集,它适用于我,但我需要使用 PostgreSQL 存储过程获取结果。
这是我的存储过程代码:
CREATE OR REPLACE PROCEDURE public.testSpCrud(
fnam text,
lnam text,
id integer,
condition integer)
LANGUAGE 'plpgsql'
AS $BODY$
declare
countOfDisc int;
BEGIN
if condition=1 then
INSERT INTO public.employee(
employeeid, lname, fname, securitylevel, employeepassword, hphonearea, hphone, cphonearea, cphone, street, city, state, zipcode, extzip, name, email, groomerid, type, commission, inactive, carrierid, notoallemployees, languageid, isdogwalker, ispetsitter, ismobilegroomer, ssma_timestamp)
VALUES (4, 'Test', 'Test', 2, 2, 32, 32, 32, 32, 32, 32,32, 32, 32, 22, 22, 2, 2, 2, false, 223,true, 223, true, true, true, '2019-08-27');
end if;
if condition =2 then
delete from Employee where employeeid=id;
end if;
if condition =3 then
update Employee set fname='Test' where employeeid=id;
end if;
if condition =4 then
Select * from Employee;
end if;
END;
$BODY$;
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function testspcrud(text,text,integer,integer) line 22 at SQL statement
SQL state: 42601
从 Postgres 13 开始,return从 PROCEDURE
中获取仍然非常有限。参见:
很可能,您爱上了 广为流传的用词不当的“存储过程”,而真正想要的是 FUNCTION
,它可以 return 一个值,一个根据其声明的行或集合。
- In PostgreSQL, what is the difference between a “Stored Procedure” and other types of functions?
- How to return result of a SELECT inside a function in PostgreSQL?
会像这样工作:
CREATE OR REPLACE FUNCTION public.testSpCrud(
fnam text,
lnam text,
id integer,
condition integer)
RETURNS SETOF Employee LANGUAGE plpgsql AS
$func$
BEGIN
CASE condition
WHEN 1 THEN
INSERT INTO public.employee(
employeeid, lname, fname, securitylevel, employeepassword, hphonearea, hphone, cphonearea, cphone, street, city, state, zipcode, extzip, name, email, groomerid, type, commission, inactive, carrierid, notoallemployees, languageid, isdogwalker, ispetsitter, ismobilegroomer, ssma_timestamp)
VALUES (4, 'Test', 'Test', 2, 2, 32, 32, 32, 32, 32, 32,32, 32, 32, 22, 22, 2, 2, 2, false, 223,true, 223, true, true, true, '2019-08-27');
WHEN 2 THEN
DELETE FROM Employee WHERE employeeid=id;
WHEN 3 THEN
UPDATE Employee SET fname='Test' WHERE employeeid=id;
WHEN 4 THEN
RETURN QUERY
SELECT * FROM Employee;
ELSE
RAISE EXCEPTION 'Unexpected condition value %!', condition;
END CASE;
END
$func$;
使用 CASE
构造进行了简化,并添加了 ELSE
子句。适应您的需求。
致电:
SELECT * FROM public.testSpCrud(...);
旁白:plpgsql 块的所有变量名在嵌套的 SQL DML 命令中都是可见的。名为 id
的变量是一个等待发生的问题。我建议使用更安全的命名约定,和/或 table-限定 DML 语句中的所有列名。一种流行的命名约定是在变量名前加上下划线。喜欢:_id
.
并考虑 SQL 和 PL/pgSQL.
中合法的小写标识符
- Are PostgreSQL column names case-sensitive?
大多数人会建议,在将 MS SQL 服务器存储过程迁移到 PostgreSQL 时,如果过程 return 是一组数据(行和列),则更改存储过程转化为函数,因为函数本质上是return组数据。但是,从 Postgres 11 开始,您可以使用游标从 PostgreSQL 过程中 return 结果集,尽管迭代结果可能很乏味。
下面演示了如何使用 INOUT 游标 return 来自 PostgreSQL 过程的一组数据:
CREATE OR REPLACE PROCEDURE test_get_data_single(
_itemID int,
INOUT _message text = '',
INOUT _result_one refcursor = 'rs_resultone',
INOUT _returnCode text = '')
LANGUAGE plpgsql
AS
$$
BEGIN
_message := 'Test message for item ' || COALESCE(_itemID, 0);
_returnCode := '';
open _result_one for
SELECT *
FROM (values (1,2,3, 'fruit', current_timestamp - INTERVAL '5 seconds'),
(4,5,6, 'veggie', current_timestamp)) as t(a,b,c,d,e);
END;
$$;
要使用,请在事务中调用过程
BEGIN;
CALL test_get_data_single(1);
FETCH ALL FROM "rs_resultone";
COMMIT;
PostgreSQL 也支持使用 Begin
/ End
:
BEGIN;
CALL test_get_data_single(2);
FETCH ALL FROM "rs_resultone";
END;
示例结果来自 DBeaver
+--------------------------+--------------+-------------+
| _message | _result_one | _returncode |
+--------------------------+--------------+-------------+
| Test message for item 2 | rs_resultone | |
+--------------------------+--------------+-------------+
+---+---+---+--------+---------------------|
| a | b | c | d | e |
+---+---+---+--------+---------------------|
| 1 | 2 | 3 | fruit | 2020-02-15 10:12:09 |
| 4 | 5 | 6 | veggie | 2020-02-15 10:12:09 |
+---+---+---+--------+---------------------|
要对结果进行更高级的处理,请使用 anonymous code block 迭代结果
DO
$$
DECLARE
_message text = '';
_returnCode text = '';
_result_one refcursor;
_result_single refcursor;
_currentRow record;
_i int;
BEGIN
CALL test_get_data_single(1, _message => _message, _result_one => _result_single, _returnCode => _returnCode);
RAISE info 'Cursor _result_single from test_get_data_single: %', _result_single;
_i := 0;
WHILE TRUE
Loop
FETCH NEXT FROM _result_single INTO _currentRow;
IF _currentRow IS NULL Then
EXIT;
END IF;
_i := _i + 1;
RAISE info '%, array: %', _i, _currentRow;
RAISE info '%, values: % % % %', _i, _currentRow.a, _currentRow.b, _currentRow.c, _currentRow.d;
END LOOP;
End
$$;
来自 DBeaver 的示例结果(查看服务器输出,使用 Ctrl+Shift+O 打开):
Cursor _result_single from test_get_data_single: <unnamed portal 261>
1, array: (1,2,3,fruit,"2020-02-14 17:19:29.612822-08")
1, values: 1 2 3 fruit
2, array: (4,5,6,veggie,"2020-02-14 17:19:34.612822-08")
2, values: 4 5 6 veggie
示例结果来自 psql:
INFO: Cursor _result_single from test_get_data_single: <unnamed portal 4>
INFO: 1, array: (1,2,3,fruit,"2020-02-14 17:22:50.81671-08")
INFO: 1, values: 1 2 3 fruit
INFO: 2, array: (4,5,6,veggie,"2020-02-14 17:22:55.81671-08")
INFO: 2, values: 4 5 6 veggie
一个过程也可以 return 两个结果集,使用单独的 refcursor
个参数:
CREATE OR REPLACE PROCEDURE test_get_data(
_itemID int,
INOUT _message TEXT = '',
INOUT _result_one refcursor = 'rs_resultone',
INOUT _result_two refcursor = 'rs_resulttwo',
INOUT _returnCode TEXT = '')
LANGUAGE plpgsql
AS
$$
BEGIN
_message := 'Test message for item ' || COALESCE(_itemID, 0);
_returnCode := '';
open _result_one for
SELECT *
FROM (values (1,2,3, 'fruit', current_timestamp - INTERVAL '5 seconds'), (4,5,6, 'veggie', current_timestamp)) as t(a,b,c,d,e);
open _result_two for
SELECT *
FROM (values ('one'), ('two'), ('three'), ('four')) as p(name);
END;
$$;
检索结果:
BEGIN;
CALL test_get_data(1);
FETCH ALL FROM "rs_resultone";
FETCH ALL FROM "rs_resulttwo";
END;
或使用展开的 anonymous code block 查看结果
DO
$$
DECLARE
_message text = '';
_returnCode text = '';
_result_one refcursor;
_result_two refcursor;
_result_single refcursor;
_currentRow record;
_i int;
BEGIN
CALL test_get_data(1, _message => _message, _result_one => _result_one, _result_two => _result_two, _returnCode => _returnCode);
RAISE info '%', _message;
RAISE info '';
RAISE info 'Cursor _result_one: %', _result_one;
_i := 0;
WHILE TRUE
Loop
FETCH NEXT FROM _result_one INTO _currentRow;
IF _currentRow IS NULL Then
EXIT;
END IF;
_i := _i + 1;
RAISE info '%, array: %', _i, _currentRow;
RAISE info '%, values: % % % %', _i, _currentRow.a, _currentRow.b, _currentRow.c, _currentRow.d;
END LOOP;
RAISE info '';
RAISE info 'Cursor _result_two: %', _result_two;
_i := 0;
WHILE TRUE
Loop
FETCH NEXT FROM _result_two INTO _currentRow;
IF _currentRow IS NULL Then
EXIT;
END IF;
_i := _i + 1;
RAISE info '%: %', _i, _currentRow;
END LOOP;
End
$$;
输出:
Test message for item 1
Cursor _result_one: <unnamed portal 263>
1, array: (1,2,3,fruit,"2020-02-14 17:25:06.528551-08")
1, values: 1 2 3 fruit
2, array: (4,5,6,veggie,"2020-02-14 17:25:11.528551-08")
2, values: 4 5 6 veggie
Cursor _result_two: <unnamed portal 264>
1: (one)
2: (two)
3: (three)
4: (four)
另一种设计模式,特别是对于通常有 add/update 数据但偶尔需要预览结果的程序,是使用 RAISE INFO
语句。例如:
If _infoOnly <> 0 Then
_infoHead := format('%-22s %-15s %-20s %-25s %-25s',
'State Change Preview',
'Parameter Name',
'Manager Name',
'Manager Type',
'Enabled (control_from_website=1)'
);
RAISE INFO '%', _infoHead;
FOR _previewData IN
SELECT PV.value || ' --> ' || _newValue AS State_Change_Preview,
PT.param_name AS Parameter_Name,
M.mgr_name AS manager_name,
MT.mgr_type_name AS Manager_Type,
M.control_from_website
FROM mc.t_param_value PV
INNER JOIN mc.t_param_type PT
ON PV.type_id = PT.param_id
INNER JOIN mc.t_mgrs M
ON PV.mgr_id = M.mgr_id
INNER JOIN mc.t_mgr_types MT
ON M.mgr_type_id = MT.mgr_type_id
INNER JOIN TmpManagerList U
ON M.mgr_name = U.manager_name
WHERE PT.param_name = 'mgractive' AND
PV.value <> _newValue AND
MT.mgr_type_active > 0
LOOP
_infoData := format('%-22s %-15s %-20s %-25s %-25s',
_previewData.State_Change_Preview,
_previewData.Parameter_Name,
_previewData.manager_name,
_previewData.Manager_Type,
_previewData.control_from_website
);
RAISE INFO '%', _infoData;
END LOOP;
_message := format('Would set %s managers to %s; see the Output window for details',
_countToUpdate,
_activeStateDescription);
示例用法(完整过程在 GitHub 上的 PNNL-Comp-Mass-Spec/DBSchema_PgSQL_DMS 存储库中):
CALL mc.EnableDisableManagers(
_enable => 1,
_managerTypeID => 11,
_managerNameList => 'Pub-80%',
_infoOnly => 1,
_includeDisabled => 0
);
示例结果:
+-----------------------------------+-------------+
| _message | _returnCode |
+-----------------------------------+-------------+
| Would set 8 managers to Active; | |
| see the Output window for details | |
+-----------------------------------+-------------+
输出window内容:
State Change Preview Parameter Name Manager Name Manager Type Enabled (control_from_website=1)
False --> True mgractive Pub-80-1 Analysis Tool Manager 1
False --> True mgractive Pub-80-2 Analysis Tool Manager 1
False --> True mgractive Pub-80-3 Analysis Tool Manager 1
False --> True mgractive Pub-80-4 Analysis Tool Manager 1
False --> True mgractive Pub-80-5 Analysis Tool Manager 1
False --> True mgractive Pub-80-6 Analysis Tool Manager 1
False --> True mgractive Pub-80-7 Analysis Tool Manager 1
False --> True mgractive Pub-80-8 Analysis Tool Manager 1
我在 PostgreSQL 11 中创建了一个存储过程来执行 CRUD 操作,它适用于 1. 创建 2. 更新 3. 删除,但是当我 运行 通过传递 Condition = 4
读取命令时select 个结果集,出现以下错误。
我已经使用 PostgreSQL 函数获取结果集,它适用于我,但我需要使用 PostgreSQL 存储过程获取结果。
这是我的存储过程代码:
CREATE OR REPLACE PROCEDURE public.testSpCrud(
fnam text,
lnam text,
id integer,
condition integer)
LANGUAGE 'plpgsql'
AS $BODY$
declare
countOfDisc int;
BEGIN
if condition=1 then
INSERT INTO public.employee(
employeeid, lname, fname, securitylevel, employeepassword, hphonearea, hphone, cphonearea, cphone, street, city, state, zipcode, extzip, name, email, groomerid, type, commission, inactive, carrierid, notoallemployees, languageid, isdogwalker, ispetsitter, ismobilegroomer, ssma_timestamp)
VALUES (4, 'Test', 'Test', 2, 2, 32, 32, 32, 32, 32, 32,32, 32, 32, 22, 22, 2, 2, 2, false, 223,true, 223, true, true, true, '2019-08-27');
end if;
if condition =2 then
delete from Employee where employeeid=id;
end if;
if condition =3 then
update Employee set fname='Test' where employeeid=id;
end if;
if condition =4 then
Select * from Employee;
end if;
END;
$BODY$;
ERROR: query has no destination for result data HINT: If you want to discard the results of a SELECT, use PERFORM instead. CONTEXT: PL/pgSQL function testspcrud(text,text,integer,integer) line 22 at SQL statement SQL state: 42601
从 Postgres 13 开始,return从 PROCEDURE
中获取仍然非常有限。参见:
很可能,您爱上了 广为流传的用词不当的“存储过程”,而真正想要的是 FUNCTION
,它可以 return 一个值,一个根据其声明的行或集合。
- In PostgreSQL, what is the difference between a “Stored Procedure” and other types of functions?
- How to return result of a SELECT inside a function in PostgreSQL?
会像这样工作:
CREATE OR REPLACE FUNCTION public.testSpCrud(
fnam text,
lnam text,
id integer,
condition integer)
RETURNS SETOF Employee LANGUAGE plpgsql AS
$func$
BEGIN
CASE condition
WHEN 1 THEN
INSERT INTO public.employee(
employeeid, lname, fname, securitylevel, employeepassword, hphonearea, hphone, cphonearea, cphone, street, city, state, zipcode, extzip, name, email, groomerid, type, commission, inactive, carrierid, notoallemployees, languageid, isdogwalker, ispetsitter, ismobilegroomer, ssma_timestamp)
VALUES (4, 'Test', 'Test', 2, 2, 32, 32, 32, 32, 32, 32,32, 32, 32, 22, 22, 2, 2, 2, false, 223,true, 223, true, true, true, '2019-08-27');
WHEN 2 THEN
DELETE FROM Employee WHERE employeeid=id;
WHEN 3 THEN
UPDATE Employee SET fname='Test' WHERE employeeid=id;
WHEN 4 THEN
RETURN QUERY
SELECT * FROM Employee;
ELSE
RAISE EXCEPTION 'Unexpected condition value %!', condition;
END CASE;
END
$func$;
使用 CASE
构造进行了简化,并添加了 ELSE
子句。适应您的需求。
致电:
SELECT * FROM public.testSpCrud(...);
旁白:plpgsql 块的所有变量名在嵌套的 SQL DML 命令中都是可见的。名为 id
的变量是一个等待发生的问题。我建议使用更安全的命名约定,和/或 table-限定 DML 语句中的所有列名。一种流行的命名约定是在变量名前加上下划线。喜欢:_id
.
并考虑 SQL 和 PL/pgSQL.
中合法的小写标识符- Are PostgreSQL column names case-sensitive?
大多数人会建议,在将 MS SQL 服务器存储过程迁移到 PostgreSQL 时,如果过程 return 是一组数据(行和列),则更改存储过程转化为函数,因为函数本质上是return组数据。但是,从 Postgres 11 开始,您可以使用游标从 PostgreSQL 过程中 return 结果集,尽管迭代结果可能很乏味。
下面演示了如何使用 INOUT 游标 return 来自 PostgreSQL 过程的一组数据:
CREATE OR REPLACE PROCEDURE test_get_data_single(
_itemID int,
INOUT _message text = '',
INOUT _result_one refcursor = 'rs_resultone',
INOUT _returnCode text = '')
LANGUAGE plpgsql
AS
$$
BEGIN
_message := 'Test message for item ' || COALESCE(_itemID, 0);
_returnCode := '';
open _result_one for
SELECT *
FROM (values (1,2,3, 'fruit', current_timestamp - INTERVAL '5 seconds'),
(4,5,6, 'veggie', current_timestamp)) as t(a,b,c,d,e);
END;
$$;
要使用,请在事务中调用过程
BEGIN;
CALL test_get_data_single(1);
FETCH ALL FROM "rs_resultone";
COMMIT;
PostgreSQL 也支持使用 Begin
/ End
:
BEGIN;
CALL test_get_data_single(2);
FETCH ALL FROM "rs_resultone";
END;
示例结果来自 DBeaver
+--------------------------+--------------+-------------+
| _message | _result_one | _returncode |
+--------------------------+--------------+-------------+
| Test message for item 2 | rs_resultone | |
+--------------------------+--------------+-------------+
+---+---+---+--------+---------------------|
| a | b | c | d | e |
+---+---+---+--------+---------------------|
| 1 | 2 | 3 | fruit | 2020-02-15 10:12:09 |
| 4 | 5 | 6 | veggie | 2020-02-15 10:12:09 |
+---+---+---+--------+---------------------|
要对结果进行更高级的处理,请使用 anonymous code block 迭代结果
DO
$$
DECLARE
_message text = '';
_returnCode text = '';
_result_one refcursor;
_result_single refcursor;
_currentRow record;
_i int;
BEGIN
CALL test_get_data_single(1, _message => _message, _result_one => _result_single, _returnCode => _returnCode);
RAISE info 'Cursor _result_single from test_get_data_single: %', _result_single;
_i := 0;
WHILE TRUE
Loop
FETCH NEXT FROM _result_single INTO _currentRow;
IF _currentRow IS NULL Then
EXIT;
END IF;
_i := _i + 1;
RAISE info '%, array: %', _i, _currentRow;
RAISE info '%, values: % % % %', _i, _currentRow.a, _currentRow.b, _currentRow.c, _currentRow.d;
END LOOP;
End
$$;
来自 DBeaver 的示例结果(查看服务器输出,使用 Ctrl+Shift+O 打开):
Cursor _result_single from test_get_data_single: <unnamed portal 261>
1, array: (1,2,3,fruit,"2020-02-14 17:19:29.612822-08")
1, values: 1 2 3 fruit
2, array: (4,5,6,veggie,"2020-02-14 17:19:34.612822-08")
2, values: 4 5 6 veggie
示例结果来自 psql:
INFO: Cursor _result_single from test_get_data_single: <unnamed portal 4>
INFO: 1, array: (1,2,3,fruit,"2020-02-14 17:22:50.81671-08")
INFO: 1, values: 1 2 3 fruit
INFO: 2, array: (4,5,6,veggie,"2020-02-14 17:22:55.81671-08")
INFO: 2, values: 4 5 6 veggie
一个过程也可以 return 两个结果集,使用单独的 refcursor
个参数:
CREATE OR REPLACE PROCEDURE test_get_data(
_itemID int,
INOUT _message TEXT = '',
INOUT _result_one refcursor = 'rs_resultone',
INOUT _result_two refcursor = 'rs_resulttwo',
INOUT _returnCode TEXT = '')
LANGUAGE plpgsql
AS
$$
BEGIN
_message := 'Test message for item ' || COALESCE(_itemID, 0);
_returnCode := '';
open _result_one for
SELECT *
FROM (values (1,2,3, 'fruit', current_timestamp - INTERVAL '5 seconds'), (4,5,6, 'veggie', current_timestamp)) as t(a,b,c,d,e);
open _result_two for
SELECT *
FROM (values ('one'), ('two'), ('three'), ('four')) as p(name);
END;
$$;
检索结果:
BEGIN;
CALL test_get_data(1);
FETCH ALL FROM "rs_resultone";
FETCH ALL FROM "rs_resulttwo";
END;
或使用展开的 anonymous code block 查看结果
DO
$$
DECLARE
_message text = '';
_returnCode text = '';
_result_one refcursor;
_result_two refcursor;
_result_single refcursor;
_currentRow record;
_i int;
BEGIN
CALL test_get_data(1, _message => _message, _result_one => _result_one, _result_two => _result_two, _returnCode => _returnCode);
RAISE info '%', _message;
RAISE info '';
RAISE info 'Cursor _result_one: %', _result_one;
_i := 0;
WHILE TRUE
Loop
FETCH NEXT FROM _result_one INTO _currentRow;
IF _currentRow IS NULL Then
EXIT;
END IF;
_i := _i + 1;
RAISE info '%, array: %', _i, _currentRow;
RAISE info '%, values: % % % %', _i, _currentRow.a, _currentRow.b, _currentRow.c, _currentRow.d;
END LOOP;
RAISE info '';
RAISE info 'Cursor _result_two: %', _result_two;
_i := 0;
WHILE TRUE
Loop
FETCH NEXT FROM _result_two INTO _currentRow;
IF _currentRow IS NULL Then
EXIT;
END IF;
_i := _i + 1;
RAISE info '%: %', _i, _currentRow;
END LOOP;
End
$$;
输出:
Test message for item 1
Cursor _result_one: <unnamed portal 263>
1, array: (1,2,3,fruit,"2020-02-14 17:25:06.528551-08")
1, values: 1 2 3 fruit
2, array: (4,5,6,veggie,"2020-02-14 17:25:11.528551-08")
2, values: 4 5 6 veggie
Cursor _result_two: <unnamed portal 264>
1: (one)
2: (two)
3: (three)
4: (four)
另一种设计模式,特别是对于通常有 add/update 数据但偶尔需要预览结果的程序,是使用 RAISE INFO
语句。例如:
If _infoOnly <> 0 Then
_infoHead := format('%-22s %-15s %-20s %-25s %-25s',
'State Change Preview',
'Parameter Name',
'Manager Name',
'Manager Type',
'Enabled (control_from_website=1)'
);
RAISE INFO '%', _infoHead;
FOR _previewData IN
SELECT PV.value || ' --> ' || _newValue AS State_Change_Preview,
PT.param_name AS Parameter_Name,
M.mgr_name AS manager_name,
MT.mgr_type_name AS Manager_Type,
M.control_from_website
FROM mc.t_param_value PV
INNER JOIN mc.t_param_type PT
ON PV.type_id = PT.param_id
INNER JOIN mc.t_mgrs M
ON PV.mgr_id = M.mgr_id
INNER JOIN mc.t_mgr_types MT
ON M.mgr_type_id = MT.mgr_type_id
INNER JOIN TmpManagerList U
ON M.mgr_name = U.manager_name
WHERE PT.param_name = 'mgractive' AND
PV.value <> _newValue AND
MT.mgr_type_active > 0
LOOP
_infoData := format('%-22s %-15s %-20s %-25s %-25s',
_previewData.State_Change_Preview,
_previewData.Parameter_Name,
_previewData.manager_name,
_previewData.Manager_Type,
_previewData.control_from_website
);
RAISE INFO '%', _infoData;
END LOOP;
_message := format('Would set %s managers to %s; see the Output window for details',
_countToUpdate,
_activeStateDescription);
示例用法(完整过程在 GitHub 上的 PNNL-Comp-Mass-Spec/DBSchema_PgSQL_DMS 存储库中):
CALL mc.EnableDisableManagers(
_enable => 1,
_managerTypeID => 11,
_managerNameList => 'Pub-80%',
_infoOnly => 1,
_includeDisabled => 0
);
示例结果:
+-----------------------------------+-------------+
| _message | _returnCode |
+-----------------------------------+-------------+
| Would set 8 managers to Active; | |
| see the Output window for details | |
+-----------------------------------+-------------+
输出window内容:
State Change Preview Parameter Name Manager Name Manager Type Enabled (control_from_website=1)
False --> True mgractive Pub-80-1 Analysis Tool Manager 1
False --> True mgractive Pub-80-2 Analysis Tool Manager 1
False --> True mgractive Pub-80-3 Analysis Tool Manager 1
False --> True mgractive Pub-80-4 Analysis Tool Manager 1
False --> True mgractive Pub-80-5 Analysis Tool Manager 1
False --> True mgractive Pub-80-6 Analysis Tool Manager 1
False --> True mgractive Pub-80-7 Analysis Tool Manager 1
False --> True mgractive Pub-80-8 Analysis Tool Manager 1