SQL:选择除某些列之外的所有列

Ada*_*tan 140 postgresql sql-standard

有没有办法访问SELECT表中的所有列,除了特定的列?从表中选择所有非 blob 或非几何列会非常方便。

就像是:

SELECT * -the_geom FROM segments;
Run Code Online (Sandbox Code Playgroud)
  • 我曾经听说这个功能被故意排除在SQL 标准之外,因为更改向表中添加列会改变查询结果。这是真的?论证有效吗?
  • 有没有解决方法,尤其是在 PostgreSQL 中?

DrC*_*sos 68

Postgres 和 SQL 标准 (AFAIK) 都不存在这样的特性。我认为这是一个非常有趣的问题,所以我用谷歌搜索了一下,在postgresonline.com上发现了一篇有趣的文章。

他们展示了一种直接从架构中选择列的方法:

SELECT 'SELECT ' || array_to_string(ARRAY(SELECT 'o' || '.' || c.column_name
        FROM information_schema.columns As c
            WHERE table_name = 'officepark' 
            AND  c.column_name NOT IN('officeparkid', 'contractor')
    ), ',') || ' FROM officepark As o' As sqlstmt
Run Code Online (Sandbox Code Playgroud)

您可以创建一个执行类似操作的函数。邮件列表中也讨论了此类主题,但总体共识几乎相同:查询模式。

我敢肯定还有其他解决方案,但我认为它们都将涉及某种神奇的 schema-queriying-foo。

顺便说一句:要小心,SELECT * ...因为这可能会降低性能

  • Bigquery“标准sql”确实有除了现在 (3认同)

小智 27

真正的答案是,您实际上无法做到。几十年来,这一直是一个要求的功能,开发人员拒绝实施它。

建议查询模式表的流行答案将无法有效运行,因为 Postgres 优化器将动态函数视为黑匣子(请参阅下面的测试用例)。这意味着不会使用索引并且不会智能地完成连接。使用某种宏系统(例如 m4)会好得多。至少它不会让优化器感到困惑(但它仍然可能让你感到困惑。)如果不分叉代码并自己编写功能或使用编程语言接口,你就会陷入困境。

我在下面写了一个简单的概念证明,展示了在 plpgsql 中非常简单的动态执行会有多糟糕的性能。另请注意,下面我必须将返回通用记录的函数强制转换为特定的行类型并枚举列。因此,除非您想为所有表重新制作此功能,否则此方法不适用于“全选但”。

test=# create table atest (i int primary key);
CREATE TABLE
test=# insert into atest select generate_series(1,100000);
INSERT 0 100000

test=# create function get_table_column(name text) returns setof record as
$$
    declare r record;
    begin
    for r in execute 'select  * from ' || $1 loop
    return next r;
    end loop;
    return; 
    end; 
$$ language plpgsql; 

test=# explain analyze select i from atest where i=999999;
                                                      QUERY PLAN                                    
----------------------------------------------------------------------------------------------------
-------------------
 Index Only Scan using atest_pkey on atest  (cost=0.29..8.31 rows=1 width=4) (actual time=0.024..0.0
24 rows=0 loops=1)
   Index Cond: (i = 999999)
   Heap Fetches: 0
 Planning time: 0.130 ms
 Execution time: 0.067 ms
(5 rows)

test=# explain analyze
    select * from get_table_column('atest') as arowtype(i int) where i = 999999;
                                                        QUERY PLAN                                  
----------------------------------------------------------------------------------------------------
-----------------------
 Function Scan on get_table_column arowtype  (cost=0.25..12.75 rows=5 width=4) (actual time=92.636..
92.636 rows=0 loops=1)
   Filter: (i = 999999)
   Rows Removed by Filter: 100000
 Planning time: 0.080 ms
 Execution time: 95.460 ms
(5 rows)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,函数调用扫描了整个表,而直接查询使用了索引(95.46 毫秒与 00.07 毫秒)。这些类型的函数可以处理任何需要以正确顺序使用索引或连接表的复杂查询.

  • 有趣的观点。这绝对是人类用户而不是代码的功能(或者我应该希望如此!)所以我可以看到让客户负责的意义。据推测,诸如扩展显示(\x on)之类的东西纯粹是在客户端实现的,而省略列应该在类似的地方实现。 (2认同)
  • 这是为什么呢?静态 SQL 也以文本形式开始,并且必须由 Postgres 编译,所以我很惊讶它会使用不同的机器来编译动态生成的 SQL。 (2认同)

mlt*_*mlt 18

实际上,从 9.4 开始的 PostgreSQL 就可以实现,其中引入了 JSONB。我在思考如何在谷歌地图(通过 GeoJSON)中显示所有可用属性的类似问题。

irc 频道上的 johto 建议尝试从 JSONB 中删除元素。

这是想法

select the_geom,
  to_jsonb(foo) - 'the_geom'::text attributes
from (
  select * from
  segments
) foo
Run Code Online (Sandbox Code Playgroud)

虽然您得到的是 json 而不是单个列,但这正是我想要的。也许 json 可以扩展回单独的列。

  • 将 json 扩展回各个列需要提及所有列名称。还可以使用 jsonb_agg,它可以更容易地解析为返回所有列的类似格式: `select jsonb_agg(to_jsonb(q) - 'col3' - 'col4') ara from (select * from table1) q` 返回为格式 { 'ara': [{'col1': xyz, 'col2': yzx'}, {'col1': wxy, 'col2': uvw}]} (2认同)

Mar*_*ian 6

您可以(不要说您应该)这样做的唯一方法是使用动态 sql 语句。查询系统视图并找到表的结构并构建正确的语句很容易(就像 DrColossos 写的那样)。

PS:为什么要在不知道/准确编写表结构的情况下选择所有/某些列?

  • 关于你的 PS: 有时我想查询一个带有几何列的表,而不显示很长的几何字符串,这会导致输出乱码。我不想指定所有列,因为可能有几十列。 (9认同)
  • 每个人都假设进行查询的人就是设计数据库的人。:-) 假设您需要查询一个包含大量字段(超过 30 个)的旧数据库以生成 excel,但是有一两个字段具有您不想提供的敏感信息。 (3认同)

Pet*_*uss 5

你永远不会*在 SQL-VIEWS 中看到...检查 \d any_view你的psql. 对于内部表示有一个(内省的)预处理


这里的所有讨论都表明,问题提案(隐含在问题和讨论中)是程序员的语法糖,而不是真正的“SQL优化问题”……好吧,我猜,它是针对80%的程序员的。

因此可以实现为“通过内省进行预解析”...当您声明一个 SQL-VIEW 时,看看 PostgreSQL 会做什么SELECT *:VIEW 构造函数转换*为所有列的列表(通过内省并在您运行创建视图源代码)。

CREATE VIEW 和 PREPARE 的实现

这是一个可行的实施方案。假设t有字段的表(id serial, name text, the_geom geom)

CREATE VIEW t_full AS SELECT * FROM t;
-- is transformed into SELECT id,name,the_geom FROM t;

CREATE VIEW t_exp_geom AS SELECT * -the_geom FROM t;
-- or other syntax as EXCEPT the_geom
-- Will be transformed into SELECT id,name FROM t;
Run Code Online (Sandbox Code Playgroud)

PREPARE 语句也是如此。

...所以,这是可能的,这就是 80% 的程序员所需要的,PREPARE 和 VIEWS 的语法糖!


注意:当然可行的语法可能不是- column_name,如果 PostgreSQL 中存在一些冲突,那么我们可以建议EXCEPT column_name
EXCEPT (column_name1, column_name2, ..., column_nameN)或其他。