Truncating display by default in postgres psql select statements
我有一个带有长文本列的表。 我希望能够选择所有列但限制文本列而无需编写每一列。
1 | SELECT * FROM resources; |
产生的输出太长而无法在psql中正确显示。 我可以通过在长列上使用
1 | SELECT id, LEFT(DATA, 50), file_format_version, ... FROM resources; |
当我查询第一个
我不知道如何使用psql的内置选项。
您可以通过@Drazen建议的功能实现您的目标 - 更简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | CREATE OR REPLACE FUNCTION f_trunc_columns(_tbl anyelement, _len INT = 25) RETURNS SETOF anyelement AS $func$ DECLARE _typ CONSTANT regtype[] := '{bpchar, varchar}'; -- types to shorten BEGIN RETURN QUERY EXECUTE ( SELECT format('SELECT %s FROM %s' , string_agg(CASE WHEN a.atttypid = 'text'::regtype -- simple case text THEN format('left(%I, %s)', a.attname, _len) WHEN a.atttypid = ANY(_typ) -- other short types THEN format('left(%I::text, %s)::%s' , a.attname, _len, format_type(a.atttypid, a.atttypmod)) ELSE quote_ident(a.attname) END -- rest , ', ' ORDER BY a.attnum) , pg_typeof(_tbl)) FROM pg_attribute a WHERE a.attrelid = pg_typeof(_tbl)::text::regclass AND NOT a.attisdropped -- no dropped (dead) columns AND a.attnum > 0 -- no system columns ); END $func$ LANGUAGE plpgsql; |
电话示例:
1 2 | SELECT * FROM f_trunc_columns(NULL::my_table); SELECT * FROM f_trunc_columns(NULL::"MySchema"."My_funny_tbl", 11); |
SQL小提琴。
笔记
-
适用于任何具有任何数据类型列的表。
-
这构建并执行以下形式的查询:
1
2SELECT"FoO_id", LEFT(c_text, 11), LEFT(c_vc, 11)::CHARACTER VARYING
FROM "FoO"; -
它仅缩短所选数据类型的列,并使其他数据类型单独使用。我包括了基本的字符类型:
bpchar 是character 和所有变体的内部名称。
varchar 是character varying 和所有变体的内部名称。
满足您的需求。 -
该函数返回所有列的原始列名称和数据类型。我将短列转换为
text ,然后输入left() ,返回text ,因此text 列不需要另一个转换。所有其他缩短类型都需要转换回原始类型。如果你截断,有些类型会破坏!所以这不适用于所有类型。 -
您可以将
LIMIT n 附加到函数调用,但是可以使用内置的LIMIT 轻松扩展该函数 - 这对于大表来说效率更高,因为plpgsql函数内的查询是独立计划的。 -
性能并不比普通的
SELECT * FROM tbl 差很多 - 除了上述LIMIT 情况或其他嵌套函数的情况。设置返回的PL / pgSQL函数通常最好不要嵌套:- PostgreSQL存储过程性能
-
我建在一个默认的最大值。长度为25个字符,将自定义长度作为第二个参数传递,或根据需要调整函数头中的默认值。
-
此功能可以安全地防止通过恶意制作的标识符进行可能的SQL注入攻击。
相关答案以及更多解释和链接:
- 用空值替换空字符串
- 重构PL / pgSQL函数以返回各种SELECT查询的输出
- 表名作为PostgreSQL函数参数
- Postgres数据类型转换
- 查询PostgreSQL中表的架构细节?
- 如何检查给定模式中是否存在表
pgAdmin的
...具有您要求的功能,顺便说一句(对于所有列):
不是真的psql,但代码可以实现一切:)
事实证明这一点非常棘手,我对最终的解决方案并不满意,因为它有点笨拙,但是它完成了工作,但它应该被视为概念证明。总是有改进和简化的空间:)
无论如何,因为没有任何内置,我不喜欢在postgres之外做这个的想法,即。 PAGER输出通过管道输送到
Python是我大多数时候选择的武器,所以我创建了一个执行截断的
让我们从包装函数开始:
1 2 3 4 5 6 7 8 9 10 | CREATE OR REPLACE FUNCTION wrapper(t text, x anyelement, l INTEGER) RETURNS setof anyelement AS $$ BEGIN -- call the logic bearing function EXECUTE format($f$select TRUNCATE('%1$s', %2$s)$f$, t, l); -- return results RETURN query EXECUTE format($f$select * FROM trunc_%1$s$f$, t); END; $$ LANGUAGE plpgsql; |
正如您所看到的,它是通过多态输入声明的,因此它可以处理您提供给它的所有表,或者它可以返回您提供给它的相同类型的表,保留所有约束,索引等(这是完成的)通过plpython函数)...所以没有进一步的麻烦,让我们看看它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | CREATE OR REPLACE FUNCTION TRUNCATE(tbl text, l INTEGER) RETURNS void AS $$ import arrow import json # Drops IF needed AND creates a TABLE TO hold your truncated results plpy.execute('drop table if exists trunc_{0}'.format(tbl)) plpy.execute('create table trunc_{0} ( like {0} including defaults including constraints including indexes )'.format(tbl)) r = plpy.execute("select * from {}".format(tbl)) FOR i IN xrange(r.nrows()): # These two lists help us GET the ORDER OF COLUMNS AND VALUES RIGHT ins = [] cols = [] FOR x IN r[i]: IF TYPE(r[i][x]) IS str: ''' Two booleans below are used for type checking, I had an example table with some json, timestamps and integers lying around so used that for testing, this way we will truncate only text-like fields, but not json. ''' ts = FALSE js = FALSE ''' Check if we can parse date or json, note that if you have a valid json stored in a text or varchar field it will still get marked as json, by digging in the information_schema you could easily add better type checking here. ''' try: arrow.get(r[i][x]) ts = TRUE EXCEPT (arrow.parser.ParserError, UnicodeDecodeError): pass try: json.loads(r[i][x]) js = TRUE EXCEPT ValueError: pass # IF it IS a string AND its NOT json OR TIMESTAMP lets TRUNCATE it # whatever you specify AS the LAST argument IN the CALL, `l` IF NOT ts AND NOT js: r[i][x] = r[i][x][:l] # Additional CHECK FOR NULLS AND ints, AND appropriate appends IF r[i][x] IS NONE: ins.append("null") elif r[i][x] IS INT: ins.append(r[i[x]]) ``` Finally we can append our values to insert, this is done inefficiently as each row will be inserted individually, again treat this as a POC, better would be to first form a list of all inserts and then fire them in one statement. ``` ELSE: ins.append("'{}'".format(r[i][x])) cols.append(x) q = 'insert into trunc_{0}({2}) values({1})'.format(tbl, ','.join(ins), ','.join(cols)) plpy.execute(q) $$ LANGUAGE plpythonu; |
如果我设法正确格式化你应该可以通过运行来调用它:
1 | SELECT * FROM wrapper(resources, NULL::resources, 50); |
再次,笨拙表明它丑陋的面孔,所以你给表名,表列类型,所以它知道要返回什么和截断的字符限制,你应该能够使用
显而易见的问题是性能,因为您将基本上重新插入整个表,这可能会有问题,但至少很容易解决。
作为事后的想法,如果您不熟悉plpython,可以通过在
希望这至少可以让你获得成为你想去的地方的一部分:)