postgresql record 使用

 

今天在做postgresql 存储过程的时候,遇到了一个问题,找了好多资料没有解决,最后经过思考终于解决了

创建一个存储过程

CREATE   OR   REPLACE   FUNCTION  test(OUT name  character   varying , OUT _cur refcursor )
  
RETURNS  record  AS
$BODY$
DECLARE
    _geom geometry;
BEGIN
  name 
=   ' 11 ' ;
  
open  _cur   for     SELECT  id,name  FROM  test_tab;
  
-- id ='222'; 
END ;
$BODY$
  LANGUAGE 
' plpgsql '  VOLATILE
  COST 
100 ;
ALTER   FUNCTION  test() OWNER  TO  pg;

就是上面这个存储过程,我需要调用这个存储过程得到输出(返回的参数)。

文档中这样描述的:

记录类型(record):

纪录变量类似行类型变量,但是它们没有预定义的结构。 它们在SELECT或者FOR命令中获取实际的行结构。 一个行变量的子结构可以在每次赋值的时候改变。 这样做的一个结果是:在一个记录变量被赋予数值之前,它没有子结构, 并且任何对其中的数据域进行访问的企图都将产生一个运行时错误。

请注意 RECORD 不是真正的数据类型,只是一个占位符。 我们还应该意识到在把一个 PL/pgSQL 函数声明为返回record类型的时候, 它和一个记录变量的概念并不完全相同,即使这个函数可能使用一个记录变量保存它的结果也如此。 在两种情况下,在书写函数的时候,实际的行结构都是不知道的,但是对于返回 record 的函数来说, 实际的结构是在调用它的查询被分析的时候决定的,而行变量可以在运行中改变其行结构。


使用方法:如获得上面函数的返回结果
select ok.name,ok._cur from test() as ok(name character varying,_out refcursor)

但是这样会报错误

ERROR:  a column definition list is only allowed for functions returning "record"

解决方法:
直接使用函数名称+"."的方式解决
select test.name,test._cur from test()
<think>好的,我需要帮助用户了解如何在PostgreSQL数据库中修改之前的SQL查询,以返回考核点对应的题目ID列表。首先,用户之前使用的是MySQL的GROUP_CONCAT函数,现在要切换到PostgreSQL,所以需要对应的函数替换。 首先,我得确认PostgreSQL中是否有类似的聚合函数。记得PostgreSQL使用的是STRING_AGG函数,而不是GROUP_CONCAT。用户之前的修改建议中提到了这一点,所以需要替换为STRING_AGG。同时,需要确保语法正确,比如参数顺序和分隔符的指定。 接下来,原来的SQL中使用了DISTINCT来去重,PostgreSQL的STRING_AGG是否支持DISTINCT?是的,STRING_AGG可以和DISTINCT一起使用,但需要注意正确的语法位置,应该是STRING_AGG(DISTINCT column, separator)。所以需要调整原来的写法。 然后,用户可能还需要注意数据类型的问题,比如question_id是否是整数类型,转换成字符串会不会有问题。不过通常在聚合时,数据库会自动处理类型转换,但可能需要显式转换,比如使用CAST或者::TEXT。 另外,用户可能关心返回的数据结构,比如questionIds是以逗号分隔的字符串,应用层需要拆分为列表。这部分需要提醒用户在应用层处理,比如使用split方法。 还需要检查GROUP BY子句是否正确,PostgreSQL对于GROUP BY的要求比较严格,所有非聚合字段必须包含在GROUP BY中。原来的查询已经按zqtp.test_point和ztp.title分组,应该是正确的,因为这两个字段是主键或唯一标识。 然后,考虑性能问题。如果数据量大,STRING_AGG可能会影响性能,需要建议用户测试数据量。另外,是否有索引优化,比如在question_id或test_point字段上建立索引。 还要注意PostgreSQL的版本,STRING_AGG在较新的版本中可用,比如9.0及以上,但用户需要确认自己的版本是否支持。如果不支持,可能需要使用array_agg和array_to_string的组合。 最后,可能需要提供一个完整的示例,展示修改后的SQL,并说明每个部分的作用,确保用户能够直接复制使用,并理解改动的地方。</think>--- ### PostgreSQL适配说明 以下是针对 **PostgreSQL 数据库**的适配调整后的SQL及详细解释: --- ### 修改后的SQL(适配PostgreSQL) ```sql SELECT zqtp.test_point AS testPointId, CASE WHEN ztp.title IS NULL THEN '默认考点' ELSE ztp.title END AS testPointName, -- 聚合题目ID为逗号分隔的字符串(PostgreSQL使用STRING_AGG) STRING_AGG(DISTINCT CAST(zer.question_id AS TEXT), ',') AS questionIds, -- 关键修改点 COUNT(*) AS testPointTotalNum, SUM(CASE WHEN zera.result = 1 THEN 1 ELSE 0 END) AS testPointRightNum, SUM(CASE WHEN zera.result = 1 THEN zera.scores::INT ELSE 0 END) AS testPointRightScore, (SUM(CASE WHEN zera.result = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*))::DECIMAL(5,2) AS userTestPointRightRate FROM zsh_exam_record zer LEFT JOIN zsh_question_test_point zqtp ON zer.question_id = zqtp.question_id LEFT JOIN zsh_test_point ztp ON zqtp.test_point = ztp.id LEFT JOIN zsh_exam_record_approve_record zera ON zera.history_id = #{historyId} AND zera.question_id = zer.question_id WHERE zer.history_id = #{historyId} GROUP BY zqtp.test_point, ztp.title; ``` --- ### 关键调整点解析 1. **聚合函数替换** - PostgreSQL 使用 `STRING_AGG(字段, 分隔符)` 代替 MySQL 的 `GROUP_CONCAT`。 - 示例:`STRING_AGG(DISTINCT CAST(question_id AS TEXT), ',')` - `CAST(question_id AS TEXT)`:确保字段类型为文本(如原字段是整数需显式转换)。 - `DISTINCT`:去重,避免同一题目ID重复出现。 - `','`:指定分隔符(可自定义为其他符号,如`';'`)。 2. **类型转换语法** - PostgreSQL 使用 `::类型` 或 `CAST(字段 AS 类型)`: - 示例:`scores::INT` 等价于 `CAST(scores AS INT)`。 3. **浮点数精度控制** - 正确率计算需显式转换为浮点类型,避免整数除法截断: ```sql (SUM(...) * 100.0 / COUNT(...))::DECIMAL(5,2) -- 保留两位小数 ``` --- ### 返回数据结构示例 | testpointid | testpointname | questionids | testpointtotalnum | testpointrightnum | ... | |-------------|---------------|-------------|-------------------|-------------------|-----| | 101 | 语法考点 | 2001,2002 | 2 | 1 | ... | | 102 | 默认考点 | 2003 | 1 | 1 | ... | --- ### PostgreSQL特性优化建议 1. **数组格式返回** 如果需要直接返回数组类型(而非字符串),使用 `ARRAY_AGG` + `ARRAY_TO_STRING`: ```sql ARRAY_TO_STRING(ARRAY_AGG(DISTINCT zer.question_id), ',') AS questionIds ``` - 优势:保留数组结构,便于后续处理。 2. **JSON格式支持** PostgreSQL 支持直接生成JSON数组(需9.4+版本): ```sql JSON_AGG(DISTINCT zer.question_id) AS questionIds -- 返回如 [2001, 2002] ``` 3. **索引优化** - 若 `zqtp.test_point` 或 `zer.question_id` 查询频繁,建议添加索引: ```sql CREATE INDEX idx_zqtp_test_point ON zsh_question_test_point(test_point); CREATE INDEX idx_zer_question_id ON zsh_exam_record(question_id); ``` --- ### 注意事项 1. **空值处理** - 如果 `zer.question_id` 可能为 `NULL`,需过滤空值避免干扰聚合: ```sql STRING_AGG(DISTINCT NULLIF(zer.question_id, '')::TEXT, ',') ``` 2. **性能调优** - 数据量较大时,`STRING_AGG` 可能较慢,建议分页查询或限制聚合范围。 3. **版本兼容性** - `STRING_AGG` 需要 PostgreSQL 9.0+,若版本过低,改用 `ARRAY_AGG` + `ARRAY_TO_STRING`。 --- ### 扩展场景:返回题目详情列表 若需同时返回题目详细信息(如标题、难度),可使用 **子查询** 或 **LATERAL JOIN**: ```sql SELECT testPointId, testPointName, -- 嵌套查询获取题目详情 (SELECT JSON_AGG(JSON_BUILD_OBJECT('id', q.id, 'title', q.title)) FROM zsh_question_bank q WHERE q.id = ANY(STRING_TO_ARRAY(questionIds, ',')::INT[]) ) AS questionDetails, testPointTotalNum, ... FROM ( -- 原查询作为子查询 SELECT zqtp.test_point AS testPointId, ...其他字段..., STRING_AGG(...) AS questionIds FROM ... ) AS subquery; ``` --- 通过以上调整,SQL可在PostgreSQL中高效返回考核点及其对应的题目ID列表,并支持灵活扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值