在 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";

                            }
                        }
                    }
                }

如果要在数据库中进行处理,需要先将文件内容获取进去。我可以想到两种方法:

  1. 创建另一个 table 并将文件内容导入其中,例如使用 copy 命令
  2. 使用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)