如何在Postgresql中的SELECT语句中创建"on-the-fly"映射表

Div*_*vey 13 sql postgresql postgresql-8.4

我正在创建一个select语句,它结合了两个表,zoneoutput基于引用的device表和zone_numberto 的映射output_type_id.zone_numberto 的映射output_type_id不会出现在数据库的任何地方,我想在select语句中"在运行中"创建它.以下是我的架构:

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)
);
Run Code Online (Sandbox Code Playgroud)

以下是一些示例数据:

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);
Run Code Online (Sandbox Code Playgroud)

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

zone_number | output_type_id
----------------------------
1           | 101
2           | 202
3           | 303 
4           | 404
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

但是,我正在寻找一种方法来创建区域nunbers到输出类型的映射,而无需创建新表并且不拼凑一堆AND/OR语句.有没有一种优雅的方法来在select语句中的两个字段之间创建映射?就像是:

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
Run Code Online (Sandbox Code Playgroud)

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

mu *_*ort 33

您可以使用VALUES内联表并加入它,只需要为其指定别名和列名称:

join (values (1, 101), (2, 202), (3, 303), (4, 304)) as map(zone_number, output_type_id)
on ...
Run Code Online (Sandbox Code Playgroud)

精细手册:

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;
Run Code Online (Sandbox Code Playgroud)

  • 美丽!您甚至可以为结果集中的列定义别名! (3认同)

Val*_*nck 7

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

SELECT * FROM 
(VALUES 
  (1, 101), 
  (2, 202), 
  (3, 303), 
  (4, 304)
) as i(zone_number, output_type_id)
Run Code Online (Sandbox Code Playgroud)

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