Postgresql

SQL:選擇除某些之外的所有列

  • May 24, 2021

有沒有辦法處理SELECT表中的所有列,除了特定的列?從表中選擇所有非 blob 或非幾何列將非常方便。

就像是:

SELECT * -the_geom FROM segments;
  • 我曾經聽說這個功能被故意從SQL 標準中排除,因為更改向表中添加列會改變查詢結果。這是真的?論據有效嗎?
  • 是否有解決方法,尤其是在 PostgreSQL 中?

Postgres 和 SQL 標準 (AFAIK) 中都不存在這樣的功能。我認為這是一個非常有趣的問題,所以我在 google 上搜尋了一下,在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

您可以創建一個執行類似操作的函式。郵件列表中也討論了此類主題,但總體共識幾乎相同:查詢架構。

我確信還有其他解決方案,但我認為它們都將涉及某種神奇的模式查詢 foo。

順便說一句:小心,SELECT * ...因為這可能會造成性能損失

真正的答案是你實際上做不到。幾十年來,這一直是一個要求的功能,開發人員拒絕實施它。

建議查詢模式表的流行答案將無法有效執行,因為 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)

如您所見,函式呼叫掃描了整個表,而直接查詢使用了索引(95.46 毫秒對 00.07 毫秒。)這些類型的函式將處理任何需要使用索引或以正確順序連接表的複雜查詢.

引用自:https://dba.stackexchange.com/questions/1957