2013-07-08 53 views
9

我創建結合兩個表,zoneoutput, 根據引用device表上的映射的select語句zone_numberoutput_type_idzone_numberoutput_type_id的映射在數據庫中的任何位置都沒有出現 ,我想在選擇 語句中「on-the-fly」創建它。下面是我的架構:如何在SELECT語句中創建一個「上即時」映射表在PostgreSQL

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。在這個例子中:處理映射是創建一個新的表

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來獲取所有的區域,再加上enabled標誌,用於設備1

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

的一種方式:

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 

不過,我正在尋找一種方式來創建區域nunbers的輸出映射不 類型創建一個新表並沒有拼湊一堆A的ND/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 

聲明:我知道最好的enabled場將在zone 表中。但是,我無法控制這件作品。我只是從應用程序方面尋找最優雅的解決方案 。謝謝!

+0

也許您可以使用VIEW? –

+0

對此我會好的,但底層映射仍然需要在select語句內(視圖內)定義,這就是我爲之分解的地方。似乎應該有一個簡單的方法來創建一個可以在select語句中使用的鍵/值「散列」來加入這兩個表。 – Divey

+0

您的'output_type'示例數據與您的輸出不匹配。 output_type_id',第一次使用101,102,103和104,而第二次使用101,202,303和404;萬歲的FKs指出這對我:) –

回答

24

可以使用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; 
+0

完美!這符合法案。 – Divey

+2

美麗!您甚至可以爲結果集中的列定義別名! –

-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 
0

所以才以補充公認的答案,下面的代碼是有效的,自足 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。)

相關問題