在 postgres 中匹配 table 的文件并确定匹配级别
Matching a file with table in postgres and identify the match level
我有一个有 4 列的 table 并且加载了数据。数据范围从 1000 到最大 200 万。
我得到一个文件(可以说制表符分隔)作为日常流程的一部分,其中包含 4 列的数据。我应该准备一份报告,其中我应该为每个列匹配增加匹配级别。
例如:
db.col1 中存在file.col1 数据;然后 matchlevel = 1
db.col2 中存在file.col2 数据;然后 matchlevel = 2
db.col3 中存在file.col3 数据;然后 matchlevel = 3
db.col4 中存在file.col4 数据;然后 matchlevel = 4
数据库中的示例数据:(所有字段都是字符串)
1367 37991 11111 sometext1
1365 37993 11112 sometext2
1369 34521 sample1 sometext1
1359 76583 sample2 sometext2
文件中的示例数据:(所有字段都是字符串)
1367 37991 11111 sometext1
1365 8993 sample3 sometext5
1369 34521 sample4 sometext6
1359 76583 sample2 sometext7
1651 875637 notpresentindb notpresentindb
输出应该是
id from file Match Level
1367 Max (all fields match in db)
1365 Low (only column1 matches
1369 Med (column1 and 2 match)
1359 High (First 3 columns match)
1651 No Match (no columns match)
目前,我正在做这个Java。声明了 4 个 arraylists 并将列中的所有数据复制到 arraylists 并使用 apache 集合查找每列数据是否存在于 4 个 arraylists 中的每一个中以用于测试目的。
但这被标记为红色,因为我们需要加载 4 列数据和 100 万条记录,并且服务器内存可能会全部消耗。
示例代码如下:
定义了 Arraylist1、Arraylist2、Arraylist3、Arraylist4
在下面的代码之前并加载了来自数据库的数据。
while ((sCurrentLine = br.readLine()) != null) {
String[] temp;
temp = sCurrentLine.split("\t");
value = "no match";
valueInt = 0;
if(arraylist1.contains(temp[0])){
value = "low";
int retval=arraylist1.indexOf(temp[0]);
if (arraylist2.get(retval).equals(temp[1])) {
value = "med";
if (arraylist3.get(retval).equals(temp[2])){
value = "High";
if (arraylist4.get(retval).equals(temp[3])) {
value = "Max";
}
}
}
}
如果要在数据库中进行处理,需要先将文件内容获取进去。我可以想到两种方法:
- 创建另一个 table 并将文件内容导入其中,例如使用
copy
命令
- 使用foreign data wrapper直接访问文件内容
一旦您能够通过 SQL 访问文件内容,您可以使用简单的外部连接来完成您想要的操作:
select fc.col1,
case
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 and fc.col4 = bt.col4 then 'Max'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 then 'High'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 then 'Med'
when fc.col1 = bt.col1 then 'Low'
else 'No Match'
end as match_level
from file_content fc
left join base_table bt on fc.col1 = bt.col1;
如果您还需要识别 base_table
中但未包含在文件中的行,则需要 full outer join
而不是左连接:
select fc.col1,
case
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 and fc.col4 = bt.col4 then 'Max'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 then 'High'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 then 'Med'
when fc.col1 = bt.col1 then 'Low'
else
case when bt.col1 is null then 'Not in database'
else 'Not in file'
end
end as match_level
from file_content fc
full join base_table bt on fc.col1 = bt.col1;
SQL小提琴示例:http://sqlfiddle.com/#!15/1ff38/2
从 Postgresql 9.1 开始,您可以使用外部数据包装器将文件视为 tables。 http://www.postgresql.org/docs/9.4/static/file-fdw.html
一旦您可以 table 看到您的 Csv,您就可以使用 SQL 功能来生成您的报告。
CREATE TABLE t (
id SERIAL PRIMARY KEY,
c1 text,
c2 text,
c3 text
) ;
CREATE EXTENSION file_fdw;
CREATE SERVER my_csv_server FOREIGN DATA WRAPPER file_fdw;
CREATE TABLE csv (
id integer,
c1 text,
c2 text,
c3 text
)
SERVER my_csv_server
OPTIONS ( filename '/home/me/data.csv', format 'csv' );
SELECT
id,
CASE
WHEN t.c1 = csv.c1 AND t.c2 = csv.c2 AND t.c3 = csv.c3 THEN
'Max'
WHEN t.c1 = csv.c1 AND t.c2 = csv.c2 THEN
'High'
WHEN t.c1 = csv.c1 THEN
'Mid'
ELSE
'Low' -- only id match
END as report
FROM
t JOIN csv USING (id)
我有一个有 4 列的 table 并且加载了数据。数据范围从 1000 到最大 200 万。
我得到一个文件(可以说制表符分隔)作为日常流程的一部分,其中包含 4 列的数据。我应该准备一份报告,其中我应该为每个列匹配增加匹配级别。
例如:
db.col1 中存在file.col1 数据;然后 matchlevel = 1
db.col2 中存在file.col2 数据;然后 matchlevel = 2
db.col3 中存在file.col3 数据;然后 matchlevel = 3
db.col4 中存在file.col4 数据;然后 matchlevel = 4
数据库中的示例数据:(所有字段都是字符串)
1367 37991 11111 sometext1
1365 37993 11112 sometext2
1369 34521 sample1 sometext1
1359 76583 sample2 sometext2
文件中的示例数据:(所有字段都是字符串)
1367 37991 11111 sometext1
1365 8993 sample3 sometext5
1369 34521 sample4 sometext6
1359 76583 sample2 sometext7
1651 875637 notpresentindb notpresentindb
输出应该是
id from file Match Level
1367 Max (all fields match in db)
1365 Low (only column1 matches
1369 Med (column1 and 2 match)
1359 High (First 3 columns match)
1651 No Match (no columns match)
目前,我正在做这个Java。声明了 4 个 arraylists 并将列中的所有数据复制到 arraylists 并使用 apache 集合查找每列数据是否存在于 4 个 arraylists 中的每一个中以用于测试目的。 但这被标记为红色,因为我们需要加载 4 列数据和 100 万条记录,并且服务器内存可能会全部消耗。
示例代码如下: 定义了 Arraylist1、Arraylist2、Arraylist3、Arraylist4 在下面的代码之前并加载了来自数据库的数据。
while ((sCurrentLine = br.readLine()) != null) {
String[] temp;
temp = sCurrentLine.split("\t");
value = "no match";
valueInt = 0;
if(arraylist1.contains(temp[0])){
value = "low";
int retval=arraylist1.indexOf(temp[0]);
if (arraylist2.get(retval).equals(temp[1])) {
value = "med";
if (arraylist3.get(retval).equals(temp[2])){
value = "High";
if (arraylist4.get(retval).equals(temp[3])) {
value = "Max";
}
}
}
}
如果要在数据库中进行处理,需要先将文件内容获取进去。我可以想到两种方法:
- 创建另一个 table 并将文件内容导入其中,例如使用
copy
命令 - 使用foreign data wrapper直接访问文件内容
一旦您能够通过 SQL 访问文件内容,您可以使用简单的外部连接来完成您想要的操作:
select fc.col1,
case
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 and fc.col4 = bt.col4 then 'Max'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 then 'High'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 then 'Med'
when fc.col1 = bt.col1 then 'Low'
else 'No Match'
end as match_level
from file_content fc
left join base_table bt on fc.col1 = bt.col1;
如果您还需要识别 base_table
中但未包含在文件中的行,则需要 full outer join
而不是左连接:
select fc.col1,
case
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 and fc.col4 = bt.col4 then 'Max'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 and fc.col3 = bt.col3 then 'High'
when fc.col1 = bt.col1 and fc.col2 = bt.col2 then 'Med'
when fc.col1 = bt.col1 then 'Low'
else
case when bt.col1 is null then 'Not in database'
else 'Not in file'
end
end as match_level
from file_content fc
full join base_table bt on fc.col1 = bt.col1;
SQL小提琴示例:http://sqlfiddle.com/#!15/1ff38/2
从 Postgresql 9.1 开始,您可以使用外部数据包装器将文件视为 tables。 http://www.postgresql.org/docs/9.4/static/file-fdw.html
一旦您可以 table 看到您的 Csv,您就可以使用 SQL 功能来生成您的报告。
CREATE TABLE t (
id SERIAL PRIMARY KEY,
c1 text,
c2 text,
c3 text
) ;
CREATE EXTENSION file_fdw;
CREATE SERVER my_csv_server FOREIGN DATA WRAPPER file_fdw;
CREATE TABLE csv (
id integer,
c1 text,
c2 text,
c3 text
)
SERVER my_csv_server
OPTIONS ( filename '/home/me/data.csv', format 'csv' );
SELECT
id,
CASE
WHEN t.c1 = csv.c1 AND t.c2 = csv.c2 AND t.c3 = csv.c3 THEN
'Max'
WHEN t.c1 = csv.c1 AND t.c2 = csv.c2 THEN
'High'
WHEN t.c1 = csv.c1 THEN
'Mid'
ELSE
'Low' -- only id match
END as report
FROM
t JOIN csv USING (id)