1

我有一个文件 university.txt,如下所示:

阿拉巴马州

航空大学
阿拉巴马农工大学
阿拉巴马州立大学
康考迪亚学院-塞尔玛
福克纳大学
亨廷顿学院
杰克逊维尔州立大学
贾德森学院
迈尔斯学院
奥克伍德学院
桑福德大学
东南圣经学院
南方基督教大学
春山学院
斯蒂尔曼学院
塔拉迪加学院
北阿拉巴马大学
南阿拉巴马大学
西阿拉巴马大学

阿拉斯加州

阿拉斯加圣经学院
阿拉斯加太平洋大学
谢尔顿杰克逊学院
阿拉斯加大学-安克雷奇
阿拉斯加大学 - 费尔班克斯
阿拉斯加大学 - 东南部

亚利桑那

美洲印第安人神召会学院
亚利桑那州立大学
亚利桑那州立大学东
亚利桑那州立大学西
德弗里大学-凤凰城
安柏瑞德航空大学
大峡谷大学
中北大学
北亚利桑那大学

.. 等等,在这种情况下,阿拉巴马州、阿拉斯加州和亚利桑那州是地点,其他地方都是大学。我想要做的是将位置加载到一个名为的表中Location,将大学加载到一个名为 的表中University,其中表Id的 是Location表的 FK University,如下所示:

CREATE TABLE Location (
Id          SERIAL PRIMARY KEY,
Name        TEXT
);

CREATE TABLE University (
Id          SERIAL PRIMARY KEY,
Location    INTEGER REFERENCES Location (Id) NOT NULL,
Name        TEXT
);

所以我想在 Postgres 中做的是这样的:

for (int i=0 until i = universities.size()  i++){
//each entry in the universities vector is a tuple with the first entry being the country/state
//and the second entry being a vector of the universities as String's
Vector tuple = (Vector)universities.get(i);
//insert into location table
String state = (String)tuple.get(0); 
Vector u = (Vector)tuple.get(1);
for(int j=0; until j =u.size(); j++){
//insert into university table with i as FK to location table

任何人都知道如何做到这一点?

4

2 回答 2

1

这是一个纯 SQL 解决方案

用于COPY将您的文件导入到一个临时表和一个带有数据修改 CTE(需要PostgreSQL 9.1或更高版本)的 DML 语句来完成其余的工作。两个步骤都应该很快:

具有单个文本列的临时表(在会话结束时自动删除):

CREATE TEMP TABLE tmp (txt text);

从文件导入数据:

COPY tmp FROM '/path/to/file.txt'

如果您从远程客户端执行此操作,请改用psql的meta 命令\copy

我的解决方案取决于问题中显示的数据格式。即:在一个城市之前和之后有一个空行。我假设导入文件中有实际的空字符串。确保在第一个城市之前有一个空字符串的前导行,以避免特殊情况。

行将按顺序插入。我将其用于以下窗口功能而无需订购。

WITH x AS (
    SELECT txt
          ,row_number() OVER () AS rn
          ,lead(txt) OVER () = '' AND
            lag(txt) OVER () = '' AS city
    FROM   tmp                -- don't remove empty rows just yet
    ), y AS (
    SELECT txt, city
          ,sum(city::int) OVER w AS id
    FROM   x
    WHERE  txt <> ''          -- remove empty rows now
    WINDOW w AS (ORDER BY rn)
    ), l AS (
    INSERT INTO location (id, name)
    SELECT id, txt
    FROM   y
    WHERE  city
    ), u AS (
    INSERT INTO university u (location, name)
    SELECT id, txt
    FROM   y
    WHERE  NOT city
    )
SELECT setval('location_id_seq', max(id))
FROM   y;

瞧。

  • CTEx基于城市前后行中的空字符串值来标记城市。

  • CTEy将城市 ( ) 的运行总和相加id,从而形成id对每个城市及其 unis 的完全有效。

  • CTElu进行插入,现在很容易。

  • finalSELECT为附加到的序列设置下一个值location.id。我们没有使用它,所以我们必须将它设置为当前最大值,否则我们会遇到重复的键错误,将来插入到位置。

于 2012-05-09T00:12:49.257 回答
1

将原始文件转换为表格是最安全的方法......然后您可以使用 COPY 上传它。

BEGIN { bl=0; body=0; header=""; } 
$0 == "" && body==1 && header!="" { header=""; body=0; bl=1; next; }
$0 == "" && body==0 { bl=1; next; }
$0 != "" && header=="" { header=$0; bl=0; next; }
$0 != "" && bl==1 && header!="" { body=1; print header, ",", $0 }

类似 AWK 的东西会将您的文件变成一个表格,然后您可以使用直接的 psql 复制语句上传该表格:

COPY university_data_file_table FROM awk-mashed-file;

那么您可以将该表转换为单独的表:

CREATE TABLE country AS SELECT DISTINCT country FROM university_data_file_table;
CREATE TABLE university AS SELECT country.id, udft.university FROM country, university_data_file_table udft WHERE udft.country = country.country;

使用 psql 脚本可以轻松编写类似的内容。正如我所说,您确实必须进行初始转换。

于 2012-05-09T00:49:16.933 回答