【问题标题】:How to create an "on-the-fly" mapping table within a SELECT statement in Postgresql如何在 Postgresql 的 SELECT 语句中创建“即时”映射表
【发布时间】:2013-07-06 03:18:03
【问题描述】:

我正在创建一个组合两个表 zoneoutput 的 select 语句, 基于引用的device 表和zone_numberoutput_type_id 的映射。 zone_numberoutput_type_id 的映射没有出现 数据库中的任何位置,我想在选择中“即时”创建它 陈述。以下是我的架构:

CREATE TABLE output_type (
    id INTEGER NOT NULL, 
    name TEXT,
    PRIMARY KEY (id)
);

CREATE TABLE device (
    id INTEGER NOT NULL,
    name TEXT,
    PRIMARY KEY (id)
);

CREATE TABLE zone (
    id SERIAL NOT NULL,
    device_id INTEGER NOT NULL REFERENCES device(id),
    zone_number INTEGER NOT NULL,
    PRIMARY KEY (id), 
    UNIQUE (zone_number)
);

CREATE TABLE output (
    id SERIAL NOT NULL,
    device_id INTEGER NOT NULL REFERENCES device(id),
    output_type_id INTEGER NOT NULL REFERENCES output_type(id),
    enabled BOOLEAN NOT NULL,
    PRIMARY KEY (id)
);

这是一些示例数据:

INSERT INTO output_type (id, name) VALUES 
(101, 'Output 1'),
(202, 'Output 2'),
(303, 'Output 3'),
(404, 'Output 4');

INSERT INTO device (id, name) VALUES 
(1, 'Test Device');

INSERT INTO zone (device_id, zone_number) VALUES 
(1, 1),
(1, 2),
(1, 3),
(1, 4);

INSERT INTO output (device_id, output_type_id, enabled) VALUES 
(1, 101, TRUE),
(1, 202, FALSE),
(1, 303, FALSE), 
(1, 404, TRUE);

我需要从给定设备的每个区域的输出表中获取关联的enabled 字段。 每个zone_number 映射到一个output_type_id。对于这个例子:

zone_number | output_type_id
----------------------------
1           | 101
2           | 202
3           | 303 
4           | 404

处理映射的一种方法是创建一个新表

CREATE TABLE zone_output_type_map (
    zone_number INTEGER,
    output_type_id INTEGER NOT NULL REFERENCES output_type(id)
);

INSERT INTO zone_output_type_map (zone_number, output_type_id) VALUES 
(1, 101),
(2, 202),
(3, 303), 
(4, 404);

并使用以下 SQL 获取设备 1 的所有区域以及 enabled 标志:

SELECT zone.*, output.enabled 
FROM zone
JOIN output 
ON output.device_id = zone.device_id
JOIN zone_output_type_map map
ON map.zone_number = zone.zone_number
AND map.output_type_id = output.output_type_id
AND zone.device_id = 1

但是,我正在寻找一种方法来创建区域编号到输出的映射 在不创建新表且不拼凑一堆 AND/OR 的情况下键入 陈述。有没有一种优雅的方式来创建两个字段之间的映射 在选择语句中?类似的东西:

SELECT zone.*, output.enabled 
FROM zone
JOIN output 
ON output.device_id = zone.device_id
JOIN (
    SELECT (
        1 => 101,
        2 => 202,
        3 => 303,
        4 => 404
    ) (zone_number, output_type_id)
) as map
ON map.zone_number = zone.zone_number
AND map.output_type_id = output.output_type_id
AND zone.device_id = 1

免责声明:我知道理想情况下 enabled 字段将存在于 zone 桌子。但是,我无法控制那件作品。我只是在寻找 应用程序方面最优雅的解决方案。谢谢!

【问题讨论】:

  • 也许你可以使用视图?
  • 我可以接受,但是底层映射仍然需要在 select 语句中(在视图中)定义,这就是我崩溃的地方。似乎应该有一种简单的方法来创建键/值“哈希”,可以在 select 语句中使用它来连接两个表。
  • 您的output_type 样本数据与您的output. output_type_id 不匹配,第一个使用101、102、103 和104,而第二个使用101、202、303 和404;万岁 FK 向我指出这一点 :)
  • 感谢@mu 的收获!我在我的问题中解决了这个问题。

标签: sql postgresql postgresql-8.4


【解决方案1】:
JOIN 
(SELECT 1 zone_number, 101 as output_type_id
 UNION ALL
 SELECT 2 zone_number, 202 as output_type_id
 UNION ALL
 SELECT 3 zone_number, 303 as output_type_id
) mappings on mappings.zone_number = zone.zone_number

【讨论】:

    【解决方案2】:

    您可以将VALUES 用作内联表并加入其中,您只需为其指定别名和列名:

    join (values (1, 101), (2, 202), (3, 303), (4, 304)) as map(zone_number, output_type_id)
    on ...
    

    来自fine manual

    VALUES 也可以用于可能写入子SELECT 的地方,例如 FROM 子句中的示例:

    SELECT f.*
      FROM films f, (VALUES('MGM', 'Horror'), ('UA', 'Sci-Fi')) AS t (studio, kind)
      WHERE f.studio = t.studio AND f.kind = t.kind;
    
    UPDATE employees SET salary = salary * v.increase
      FROM (VALUES(1, 200000, 1.2), (2, 400000, 1.4)) AS v (depno, target, increase)
      WHERE employees.depno = v.depno AND employees.sales >= v.target;
    

    【讨论】:

    • 完美!这符合要求。
    • 漂亮!您甚至可以为结果集中的列定义别名!
    【解决方案3】:

    因此,为了补充已接受的答案,以下代码是一个有效的自包含 Postgresql 表达式,它将评估为与列 (zone_number, output_type_id) 的“内联”关系:

    SELECT * FROM 
    (VALUES 
      (1, 101), 
      (2, 202), 
      (3, 303), 
      (4, 304)
    ) as i(zone_number, output_type_id)
    

    (单独的(VALUES ... AS ...) 部分不会产生有效的表达式,这就是我添加SELECT * FROM 的原因。)

    【讨论】:

      猜你喜欢
      • 2021-01-28
      • 2019-12-14
      • 2017-12-20
      • 2020-09-27
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2011-12-24
      相关资源
      最近更新 更多