将数据从1:N关系复制到单个表(有效)

时间:2018-03-23 19:27:06

标签: sql oracle postgresql

我们在1:N关系中有2个表。例如,项目及其自定义属性。

CREATE TABLE item (
  id BIGINT PRIMARY KEY
);

CREATE TABLE property (
  id    BIGINT PRIMARY KEY,
  oneFK BIGINT REFERENCES item (id),
  key   CHARACTER VARYING(5),
  value CHARACTER VARYING(5)
);

让我们有一些演示数据:

INSERT INTO item VALUES (1);
INSERT INTO property VALUES
  (1, 1, 'key1', 'val1'),
  (2, 1, 'key2', 'val2'),
  (3, 1, 'key3', 'val3');

我们在这些表格中有数百万行后,要求他们导出'他们到另一个定义为:

的表
CREATE TABLE flat (
  id   BIGINT PRIMARY KEY,
  key1 CHARACTER VARYING(5),
  key2 CHARACTER VARYING(5),
  key3 CHARACTER VARYING(5)
);

如此天真的插入可能看起来像:

INSERT INTO flat (id, key1, key2, key3)
  SELECT
    i.id,
    (SELECT p.value
     FROM property p
     WHERE p.oneFK = i.id AND p.key = 'key1'),

    (SELECT p.value
     FROM property p
     WHERE p.oneFK = i.id AND p.key = 'key2'),

    (SELECT p.value
     FROM property p
     WHERE p.oneFK = i.id AND p.key = 'key3')
  FROM item i;

但是会有5个嵌套的选择,每个都在相当大的表中。所以我根本不喜欢这样。有不同的提议,我更喜欢它,怀疑它实际上会表现得更好,并且发现它有点荒谬:

INSERT INTO flat
  SELECT
    i.id,
    --lots of other properties
    max(CASE WHEN key = 'key1'
      THEN 'key1'
        ELSE NULL END)
  --so on.
  FROM item i
    JOIN property p ON i.id = p.oneFK
  GROUP BY i.id --, lots of other properties

那么实际建议和执行此任务的有效方法是什么?理想情况下,在通用sql中,oracle / postgres特定(理想情况下都是)也很好。

1 个答案:

答案 0 :(得分:2)

第二个提案"可能是这样做的方法(使用条件聚合来转动)。但它与您在问题中的内容略有不同:

INSERT INTO flat
  ( id /* , other columns */, key1, key2, key3 )
SELECT id -- , other columns
     , MAX(CASE WHEN key = 'key1' THEN val END) AS key1 -- ELSE NULL is superfluous
     , MAX(CASE WHEN key = 'key2' THEN val END) AS key2
     , MAX(CASE WHEN key = 'key3' THEN val END) AS key3
 FROM item i JOIN property p
   ON i.id = p.oneFK
GROUP BY i.id;

也就是说,我假设您希望存储在val列中的值而不是key列中存储的密钥索引。顺便说一下,我希望你没有一个名为key的列,因为这是一个保留字。

希望这会有所帮助。这应该至少在Oracle和Postgres中都有效。