如何将公共数据从不同的模式插入临时表?

我不知道如何解决这个问题:

我们从各种在线供应商(亚马逊,Newegg等)导入订单信息。 每个供应商都有自己的特定术语和结构,用于我们已镜像到数据库中的订单。 我们的数据导入到数据库中没有问题,但我面临的问题是编写一个方法,从数据库中提取必需的字段,而不管模式如何。

例如,假设我们有以下结构:

Newegg结构:

"OrderNumber" integer NOT NULL, -- The Order Number "InvoiceNumber" integer, -- The invoice number "OrderDate" timestamp without time zone, -- Create date. 

亚马逊结构:

 "amazonOrderId" character varying(25) NOT NULL, -- Amazon's unique, displayable identifier for an order. "merchant-order-id" integer DEFAULT 0, -- A unique identifier optionally supplied for the order by the Merchant. "purchase-date" timestamp with time zone, -- The date the order was placed. 

如何选择这些项目并将它们放入临时表中以供我查询?

临时表可能如下所示:

 "OrderNumber" character varying(25) NOT NULL, "TransactionId" integer, "PurchaseDate" timestamp with time zone 

据我所知,有些数据库代表一个带整数的订单号,而其他数据库则代表一个不同的字符; 处理我计划将数据类型转换为String值。

有没有人建议我阅读有关这将有助于我解决这个问题?

我不需要一个确切的答案,只需要朝着正确的方向轻推。

Java将使用这些数据,因此如果任何特定的Java类有帮助,请随时提出建议。

首先,您可以创建一个VIEW来提供此function:

 CREATE VIEW orders AS SELECT '1'::int AS source -- or any other tag to identify source ,"OrderNumber"::text AS order_nr ,"InvoiceNumber" AS tansaction_id -- no cast .. is int already ,"OrderDate" AT TIME ZONE 'UTC' AS purchase_date -- !! see explanation FROM tbl_newegg UNION ALL -- not UNION! SELECT 2 "amazonOrderId" ,"merchant-order-id" ,"purchase-date" FROM tbl_amazon; 

您可以像查看任何其他表一样查询此视图:

 SELECT * FROM orders WHERE order_nr = 123 AND source = 2; 
  • 如果order_nr不是唯一的,则source是必需的。 您如何保证不同来源的唯一订单号?

  • timestamp without time zonetimestamp without time zone在全局上下文中是不明确的。 它与时区有关。 如果混合timestamptimestamptz ,则需要使用AT TIME ZONE结构将timestamp放在特定时区以使其工作。 有关更多说明,请阅读此相关答案 。

    我使用UTC作为时区,您可能想要提供另一个。 简单的演员"OrderDate"::timestamptz将假设您当前的时区。 AT TIME ZONE应用于timestamp导致timestamptz 。 这就是为什么我没有添加另一个演员。

  • 虽然你可以 ,但我建议不要在PostgreSQL中使用驼峰式标识符。 避免多种可能的混淆。 请注意我提供的小写标识符(没有现在不必要的双引号)。

  • 不要将varchar(25)用作order_nr类型。 如果必须是一个字符串,只需使用没有任意长度修饰符的text 。 如果所有订单号仅由数字组成,则integerbigint会更快。

性能

实现这一目标的一种方法是实现视图。 即,将结果写入(临时)表:

 CREATE TEMP TABLE tmp_orders AS SELECT * FROM orders; ANALYZE tmp_orders; -- temp tables are not auto-analyzed! ALTER TABLE tmp_orders ADD constraint orders_pk PRIMARY KEY (order_nr, source); 

需要一个索引。 在我的示例中,主键约束自动提供索引。

如果表很大,请确保创建临时表之前有足够的临时缓冲区来处理RAM。 否则它实际上会减慢你的速度。

 SET temp_buffers = 1000MB; 

必须是第一次调用会话中的临时对象。 不要在全局范围内将其设置为高,仅适用于您的会话。 无论如何,临时表会在会话结束时自动删除。

要估计您需要多少RAM,请创建一次表并测量:

 SELECT pg_size_pretty(pg_total_relation_size('tmp_orders')); 

有关dba.SE上此相关问题下的对象大小的更多信息 。

如果您必须在一个会话中处理大量查询,则只需支付所有开销。 对于其他用例,还有其他解决方案。 如果您在查询时知道源表,那么将查询定向到源表会快得多。 如果你不这样做,我会再次质疑你的order_nr的唯一性。 事实上,如果确保它是唯一的,你可以删除我介绍的列source

对于仅一个或几个查询,使用视图而不是物化视图可能会更快。

我还会考虑一个plpgsql函数 ,它一个接一个地查询一个表,直到找到记录。 考虑到开销,考虑几个查询可能会更便宜。 当然需要每个表的索引。

另外,如果您坚持使用order_nr textvarchar ,请考虑使用COLLATE "C"

听起来你需要创建一个抽象类来定义与数据交互的基础知识,然后为每个需要访问的数据库模式派生一个类。 这将允许核心代码在单个对象类型上运行,然后每个实现都可以以特定于该数据库模式的forms指定查询。

就像是:

 public class Order { private String orderNumber; private BigDecimal orderTotal; ... etc ... } public abstract class AbstractOrderInformation { public abstract ArrayList getOrders(); ... } 

与Neweggclass级:

 public class NeweggOrderInformation extends AbstractOrderInformation { public ArrayList getOrders() { ... do the work of getting the newegg order } ... } 

然后,您可以拥有任意数量的格式,当您需要信息时,您可以迭代所有实现并从每个实现获取订单。