有没有更简洁的方法将查询结果转换为类型?

Posted

技术标签:

【中文标题】有没有更简洁的方法将查询结果转换为类型?【英文标题】:Is there a more succinct way to cast query results to a type? 【发布时间】:2014-07-23 18:33:00 【问题描述】:

我经常将查询结果转换为用户定义的类型。考虑这个简单的例子:

test=# create type test_type as  (a int, b int);
CREATE TYPE
test=# create table test_table (a int, b int);
CREATE TABLE
test=# insert into test_table values (1,2);
INSERT 0 1
test=# select r::test_type from (select * from test_table t) as r;
   r   
-------
 (1,2)
(1 row)

对于我的很多查询来说,有一个子查询是必要的,而且效果很好。但是,有时它是从表到类型的简单 1 对 1 映射,就像上面的示例一样。

有没有更简单的表达方式?

当我尝试对我来说显而易见的事情时,我得到了错误:

test=# select t::test_type from test_table t;
ERROR:  cannot cast type test_table to test_type
LINE 1: select t::test_type from test_table t;
                ^

【问题讨论】:

考虑更新我的答案。 【参考方案1】:

您可以为此使用带有通配符列扩展的 ROW 构造。

regress=> select ROW(t.*)::testtype from testtable t;
  row  
-------
 (1,2)
(1 row)

【讨论】:

我试过 (t.*)::test_type 假设 (t.*) 会返回一个 row 但没有注意到它没有。由于它不起作用,我没有费心尝试显式的row 构造。为什么(t.*) 不返回一行?我想这是一些编译问题。 我也尝试过 (t.*)::test_type 在我的“猜测”中思考同样的事情。我假设 (t.*) 也会返回一行。 我对 Craig 做了更多研究,来自postgresql.org/docs/9.3/static/sql-expressions.html 4.2.13 “当列表中有多个表达式时,关键字 ROW 是可选的” @bhirt 是的...我认为在解析时 t.* 仍然是一个表达式。看起来仍然很奇怪。如果时间允许,我会调查一下,看看解析器和重写器到底在做什么。 @ClodoaldoNeto 在 Pg 中的通配符扩展有点 hacky。它本质上是解析阶段中途的宏扩展,这会导致一些有趣的奇怪现象。尽管如此,我希望 (t.*)::sometype 自己工作,但很惊讶它没有。【参考方案2】:

简单一点

select t::test_type
from (table test_table) t;

或创建自己的演员表

create function test_table_2_test_type (test_table_value test_table)
returns test_type as $$
    select test_table_value.a, test_table_value.b;
$$ language sql;

create cast (test_table as test_type)
with function test_table_2_test_type (test_table);

select t::test_type 
from test_table t;
   t   
-------
 (1,2)

http://www.postgresql.org/docs/current/static/sql-createcast.html

【讨论】:

对于像我这样想知道TABLE test_table 示例的人来说,它只是shorthand for SELECT * FROM。我也不知道您可以只在 SELECT 列表中列出表名,就好像它是这样的列,但是我从来没有遇到过需要...【参考方案3】:

铸造技术

或者您可以转换为 text 作为中间类型,因为 everything 都可以转换为 text 和来自 text

SELECT t::text::test_type FROM test_table t;

这是针对各种类似问题的“包罗万象”的临时解决方案,您知道类型是兼容的,但缺少直接转换。

ROW 构造函数作为 demonstrated by @Craig 在这种情况下更优雅。 创建像demonstrated by @Clodoaldo 这样的新演员表更适合您要经常使用的案例。

但是,更好的解决方案是消除问题

简单的解决方案:只使用表格类型

对于演示的简单案例,根本不要创建额外的类型。使用隐式自动创建的类型test_table。 Per documentation:

CREATE TABLE 还会自动创建一个数据类型,表示 表中一行对应的复合类型。

所以,只是:

CREATE TABLE test_table (a int, b int);
INSERT INTO test_table VALUES (1,2);

SELECT r FROM test_table r;
   r   
-------
 (1,2)

但您问题中的演示可能只是一个简化。对于一般解决方案:

多个表共享同一类型

Postgres 被某些人称为 ORDBMS(对象关系数据库管理系统)是有原因的。使用类型表

显式创建通用类型或重用“主”表的隐式类型。 这是.. .. 不是 inheritance. .. 不同于CREATE TABLE t (LIKE master) ..不同于CREATE TABLE t AS SELECT * FROM master LIMIT 0

Per documentation:

OF type_name

创建一个类型表,该表从指定的复合类型(名称可选模式限定)中获取其结构。一个打字 表与其类型相关;例如,如果该表将被删除 类型被删除(DROP TYPE ... CASCADE)。

创建类型表时,列的数据类型由底层复合类型决定,不指定 通过CREATE TABLE 命令。但是CREATE TABLE 命令可以添加 表的默认值和约束,并且可以指定存储参数。

食谱

CREATE TYPE master AS (a int, b int);

或者

CREATE TABLE master (a int, b int);

然后使用该类型创建更多相同类型的表:

CREATE TABLE table1 OF master;
CREATE TABLE table2 OF master;

INSERT INTO table1 VALUES (1,2);
INSERT INTO table2 VALUES (1,2);
SELECT r FROM table1 r;          -- returns composite type "table1"
SELECT r::master FROM table1 r; -- returns composite type "master"

复合类型mastertable1table2 100% 相同,可以自动相互转换。

【讨论】:

【参考方案4】:

如果我不厌其烦地创建一个新类型,我想我会在 create table 语句中使用它。

create table test_table (t test_type);
insert into test_table values ((2, 3));
-- No cast needed here.
select * from test_table;
吨 测试类型 -- (2, 3)
-- No cast needed here.
select t from (select * from test_table) x;
吨 测试类型 -- (2, 3)

如果您必须即时制造“test_type”类型的值,请使用行构造函数和类型转换。我认为 "::" 语法比 CAST() 更简洁,但两者都有效。

select (2, 3)::test_type 
排 测试类型 -- (2, 3)

【讨论】:

如果我没看错其他示例,这并不完全等同:您创建了一个包含单个多值列的表,但其他查询从多值列中获取一行- 列表。 我认为我回答的最后一部分“如果你必须制造一个类型为 'test_type' 的值”与其他人所说的类似。 (我使用文字;列的工作方式相同。)但我的主要观点是,在表定义中使用用户定义的类型可以完全避免类型转换的需要。 还不错;它确实带来了主要的缺点,即您 必须 引用该复合行类型,因为 SELECT a FROM test_table 不再有效。您也不能轻松地创建引用各个字段的索引、约束等。 很容易在旁观者的眼中。如果有充分的理由拥有复合类型——比如内在的datetimestamppoint 等——那么select (t).a from test_table 的价格并不是很高付钱。 PostgreSQL 支持表达式索引,包括复合类型的字段。 @IMSoP:你们可能都对typed tables 感兴趣,以求两全其美。我在答案中添加了详细信息。

以上是关于有没有更简洁的方法将查询结果转换为类型?的主要内容,如果未能解决你的问题,请参考以下文章

将 MongoDB 查询结果转换为 JSONArray

将 MySql DateTime 类型转换为更友好的东西

将可空引用类型转换为不可空引用类型,不那么冗长

如何将 SQL 查询结果转换为 PANDAS 数据结构?

查询Mysql表之后将结果转换为json时如何能够保持字段的原有数据类型?

我无法将 SQL 选择查询结果转换为位