在PSQL脚本中访问外部XML文件作为变量(来自bash脚本)

Accessing external XML files as variables in a PSQL script (sourced from a bash script)

在这个例子之后,我在* .sql脚本中使用PostgreSQL变量时遇到问题:

  • 我想使用BASH脚本迭代大量XML数据文件

  • BASH脚本将XML文件名分配给变量,该变量将传递给SQL脚本

  • 由该BASH脚本调用的SQL脚本将这些数据加载到PostgreSQL中

如果我直接获取XML文件,则没有问题; 但是,在我的SQL脚本中,我无法访问该变量:

在我的SQL脚本(hmdb.sql)中,我可以访问PSQL变量:bash_var(从BASH脚本传递):

1
2
3
\echo '
EXTERNAL VARIABLE (="datafile", HERE):' :bash_var '
'

和/或直接引用XML文件,

1
datafile text := 'hmdb/hmdb.xml';

但不是变量:

1
datafile text := 'bash_var';

hmdb.sh

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

DATA_DIR=data/

for file in $DATA_DIR/*.xml
  do
    bash_var=$(echo ${file##*/})
    echo $bash_var
    psql -d hmdb -v bash_var=$bash_var -f hmdb.sql
done


好的,这是我的解决方案。

我在Persagen.com博客上发布了更详细的答案。

基本上,我决定废除DO $$DECLARE ...方法(在SO 49950384中描述),以支持下面的简化方法。

然后,我可以访问BASH / PSQL共享变量:bash_var,因此:

1
xpath('//metabolite', XMLPARSE(DOCUMENT convert_from(pg_read_binary_file(:'bash_var'))))

这是一个示例SQL脚本,说明了这种用法:

hmdb.sql

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
\c hmdb

CREATE TABLE hmdb_identifiers (
  id SERIAL,
  accession VARCHAR(15) NOT NULL,
  name VARCHAR(300) NOT NULL,
  cas_number VARCHAR(12),
  pubchem_cid INT,
  PRIMARY KEY (id),
  UNIQUE (accession)
);

\echo '
[hmdb.sql] bash_var:'
:bash_var '
'


-- UPDATE (2019-05-15): SEE MY COMMENTS BELOW RE: TEMP TABLE!
CREATE TEMP TABLE tmp_table AS
SELECT
  (xpath('//accession/text()', x))[1]::text::varchar(15) AS accession
  ,(xpath('//name/text()', x))[1]::text::varchar(300) AS name
  ,(xpath('//cas_registry_number/text()', x))[1]::text::varchar(12) AS cas_number
  ,(xpath('//pubchem_compound_id/text()', x))[1]::text::int AS pubchem_cid
-- FROM unnest(xpath('//metabolite', XMLPARSE(DOCUMENT convert_from(pg_read_binary_file('hmdb/hmdb.xml'), 'UTF8')))) x
FROM unnest(xpath('//metabolite', XMLPARSE(DOCUMENT convert_from(pg_read_binary_file(:'bash_var'), 'UTF8')))) x
;

INSERT INTO hmdb_identifiers (accession, name, cas_number, pubchem_cid)
  SELECT lower(accession), lower(name), lower(cas_number), pubchem_cid FROM tmp_table;

DROP TABLE tmp_table;

SQL脚本说明:

  • 在xpath语句中,我根据Postgres表模式重新构造::text(例如:::text::varchar(15))。

  • 更重要的是,如果我没有在xpath语句中重新设置数据类型并且字段条目(例如name长度)超过SQL varchar(300)长度限制,则这些数据会引发PSQL错误并且表未更新(即空白)表结果)。

我在这个Gist上传了这个答案中使用的XML数据文件

https://gist.github.com/victoriastuart/d1b1959bd31e4de5ed951ff4fe3c3184

直接链接:

  • hmdb_metabolites_5000-01.xml

  • hmdb_metabolites_5000-02.xml

  • hmdb_metabolites_5000-03.xml

  • 资料来源:HMDB.ca

    • 引文

更新(2019-05-15)

在后续工作中,详细内容在我的研究博客文章Exporting Plain Text to PostgreSQL中,我直接将XML数据加载到PostgreSQL中,而不是使用临时表。

TL / DR。在该项目中,我观察到以下改进。

1
2
3
Parameter | Temp Tables  | Direct Import | Reduction
    Time: | 1048 min     | 1.75 min      | 599x
   Space: | 252,000 MB   | 18 MB         | 14,000x