在 PSQL 脚本中访问外部 XML 文件作为变量(来自 bash 脚本)
Accessing external XML files as variables in a PSQL script (sourced from a bash script)
在 this example 之后,我在 *.sql 脚本中使用 PostgreSQL 变量时遇到问题:
我想遍历多个 XML 数据文件,使用 BASH 脚本
BASH 脚本将 XML 文件名分配给变量,该变量传递给 SQL 脚本
SQL 脚本,由 BASH 脚本调用,将这些数据加载到 PostgreSQL
如果我直接获取 XML 文件,没有问题;但是,我无法在我的 SQL 脚本中访问该变量:
在我的 SQL 脚本 (hmdb.sql
) 中,我可以访问 PSQL 变量 :bash_var
(从 BASH 脚本传递):
\echo '\nEXTERNAL VARIABLE (= "datafile", HERE):' :bash_var '\n'
and/or直接引用XML文件,
datafile text := 'hmdb/hmdb.xml';
但不是变量:
datafile text := 'bash_var';
hmdb.sh
#!/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
好的,这是我的解决方案。
我 post 我 Persagen.com blog 上的更详细的答案。
基本上,我决定废除 DO $$DECLARE ...
方法(在 SO 49950384 中描述)以支持下面的简化方法。
然后我可以访问 BASH / PSQL 共享变量,:bash_var
,因此:
xpath('//metabolite', XMLPARSE(DOCUMENT convert_from(pg_read_binary_file(:'bash_var'))))
这是一个示例 SQL 脚本,说明了该用法:
hmdb.sql
\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 '\n[hmdb.sql] bash_var:' :bash_var '\n'
-- 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 table 模式重写了 ::text
(例如:::text::varchar(15)
)。
更重要的是,如果我 not 重铸 xpath 语句中的数据类型并且字段条目(例如 name
长度)超过 SQL varchar(300)
长度限制,这些数据引发了 PSQL 错误并且 table 没有更新(即空白 table 结果)。
我在这个 Gist
上传了这个答案中使用的 XML 数据文件
https://gist.github.com/victoriastuart/d1b1959bd31e4de5ed951ff4fe3c3184
直接链接:
来源:HMDB.ca
更新 (2019-05-15)
在后续工作中,在我的研究博客post Exporting Plain Text to PostgreSQL中有详细说明,我直接将XML数据加载到PostgreSQL,而不是使用temp tables.
TL/DR. 在该项目中,我观察到以下改进。
Parameter | Temp Tables | Direct Import | Reduction
Time: | 1048 min | 1.75 min | 599x
Space: | 252,000 MB | 18 MB | 14,000x
在 this example 之后,我在 *.sql 脚本中使用 PostgreSQL 变量时遇到问题:
我想遍历多个 XML 数据文件,使用 BASH 脚本
BASH 脚本将 XML 文件名分配给变量,该变量传递给 SQL 脚本
SQL 脚本,由 BASH 脚本调用,将这些数据加载到 PostgreSQL
如果我直接获取 XML 文件,没有问题;但是,我无法在我的 SQL 脚本中访问该变量:
在我的 SQL 脚本 (hmdb.sql
) 中,我可以访问 PSQL 变量 :bash_var
(从 BASH 脚本传递):
\echo '\nEXTERNAL VARIABLE (= "datafile", HERE):' :bash_var '\n'
and/or直接引用XML文件,
datafile text := 'hmdb/hmdb.xml';
但不是变量:
datafile text := 'bash_var';
hmdb.sh
#!/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
好的,这是我的解决方案。
我 post 我 Persagen.com blog 上的更详细的答案。
基本上,我决定废除 DO $$DECLARE ...
方法(在 SO 49950384 中描述)以支持下面的简化方法。
然后我可以访问 BASH / PSQL 共享变量,:bash_var
,因此:
xpath('//metabolite', XMLPARSE(DOCUMENT convert_from(pg_read_binary_file(:'bash_var'))))
这是一个示例 SQL 脚本,说明了该用法:
hmdb.sql
\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 '\n[hmdb.sql] bash_var:' :bash_var '\n'
-- 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 table 模式重写了
::text
(例如:::text::varchar(15)
)。更重要的是,如果我 not 重铸 xpath 语句中的数据类型并且字段条目(例如
name
长度)超过 SQLvarchar(300)
长度限制,这些数据引发了 PSQL 错误并且 table 没有更新(即空白 table 结果)。
我在这个 Gist
上传了这个答案中使用的 XML 数据文件https://gist.github.com/victoriastuart/d1b1959bd31e4de5ed951ff4fe3c3184
直接链接:
来源:HMDB.ca
更新 (2019-05-15)
在后续工作中,在我的研究博客post Exporting Plain Text to PostgreSQL中有详细说明,我直接将XML数据加载到PostgreSQL,而不是使用temp tables.
TL/DR. 在该项目中,我观察到以下改进。
Parameter | Temp Tables | Direct Import | Reduction
Time: | 1048 min | 1.75 min | 599x
Space: | 252,000 MB | 18 MB | 14,000x