2013-07-08 2 views
9

Я создаю оператор выбора, который сочетает в себе две таблицы, zone и output, на основе ссылочного device таблицы и на отображение zone_number - output_type_id. Отображение zone_number до output_type_id не отображается в любой точке базы данных, и я хотел бы создать его «на лету» в выписке . Ниже моя схема:Как создать «на лету» таблицу сопоставления в ЗЕЬЕСТ в 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. Для этого примера:

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, чтобы получить все зоны, плюс 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 

Однако, я ищу способ, чтобы создать отображение зоны 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. output_type_id', первый использует 101, 102, 103 и 104, тогда как второй использует 101, 202, 303 и 404; hooray для 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.)

 Смежные вопросы

  • Нет связанных вопросов^_^