Как избежать повторения длинного ИСПРАВЛЕННОГО подзапроса? - PullRequest
1 голос
/ 05 августа 2009

Вот код, который поможет вам понять мой вопрос:

create table con ( content_id number);
create table mat ( material_id number, content_id number, resolution number, file_location varchar2(50), file_size number);
create table con_groups (content_group_id number, content_id number);

insert into con values (99);
insert into mat values (1, 99, 7, 'C:\foo.jpg', 1024);
insert into mat values (2, 99, 2, '\\server\xyz.mov', 350000);
insert into mat values (3, 99, 5, '\\server2\xyz.wav', 175000);
insert into con values (100);
insert into mat values (4, 100, 5, 'C:\bar.png', 2048);
insert into mat values (5, 100, 3, '\\server\xyz.mov', 27400);
insert into mat values (6, 100, 7, '\\server2\xyz.wav', 400);

insert into con_groups values (10, 99);
insert into con_groups values (10, 100);

SELECT m.material_id, 
       m.content_id,
       (SELECT max(file_location) keep (dense_rank first order by resolution desc)                  
          FROM mat
         WHERE mat.content_id = m.content_id
        /* AND ...
           AND ...
           AND ... */) special_mat_file_location,
       (SELECT max(file_size) keep (dense_rank first order by resolution desc)
          FROM mat
         WHERE mat.content_id = m.content_id
        /* AND ...
           AND ...
           AND ... */) special_mat_file_size
  FROM mat m
 WHERE m.material_id IN (select material_id
                           from mat
                     inner join con on con.content_id = mat.content_id
                     inner join con_groups on con_groups.content_id = con.content_id
                          where con_groups.content_group_id = 10);

Я поместил закомментированные AND, чтобы подчеркнуть, что это упрощенный пример; подзапрос в моем реальном запросе является более сложным с большим количеством критериев.

Моя проблема: я хочу избежать повторения всех критериев в подзапросе для обоих столбцов (file_location and file_size), потому что критерии абсолютно одинаковы. Я бы с удовольствием использовал Common Table Expressions (то есть факторинг подзапроса с использованием предложения WITH), но не могу из-за «WHERE mat.content_id = m.content_id» в подзапросе, что делает его коррелированным подзапросом. Насколько я понимаю, нельзя учитывать коррелированные подзапросы, используя предложение WITH. По этой же причине я также не могу поместить этот подзапрос в виде встроенного представления (или производной таблицы) в предложении FROM.

Как я могу включить критерии один раз и добавить более одного столбца в набор результатов с коррелированным подзапросом?

Ответы [ 2 ]

2 голосов
/ 05 августа 2009

Использовать факторинг подзапроса (так его называет Oracle - это называется выражением общих таблиц в SQL Server). Поддерживается 9i +:

WITH file AS (
  SELECT t.content_id,
         MAX(t.file_location) keep (DENSE_RANK t.first ORDER BY t.resolution DESC) 'fileLocation',
         MAX(t.file_size) keep (DENSE_RANK t.first ORDER BY t.resolution DESC) 'fileSize'
    FROM mat t
GROUP BY t.content_id)
SELECT m.material_id, 
       m.content_id,
       f.fileLocation,
       f.fileSize
  FROM mat m
  JOIN file f ON f.content_id = m.content_id

Предназначено для повторного использования в виде встроенного представления. Вы обобщаете представление и определяете конкретную фильтрацию для разных экземпляров в предложении JOIN. Вам необходимо предоставить столбцы для объединения в предложении SELECT - см. content_id в качестве примера.

Коррелированный подзапрос означает, что он может быть переписан как JOIN - корреляция является критерием JOIN.

Вы можете определить несколько представлений в Факторинге подзапроса - если бы вы предоставили больше деталей, я мог бы лучше адаптировать ответ.

0 голосов
/ 06 августа 2009

Я думаю, что понял. Я смог просто взять первичный ключ «специального» материала и обернуть основной запрос в другой слой, например:

         SELECT x.material_id,
                x.content_id,
                sp_m.file_location,
                sp_m.file_size
           FROM (SELECT m.material_id, 
                        m.content_id,
                        (SELECT max(material_id) keep (dense_rank first order by resolution desc)                  
                           FROM mat
                          WHERE mat.content_id = m.content_id
                         /* AND ...
                            AND ...
                            AND ... */) special_mat_primary_key
                   FROM mat m
                  WHERE m.material_id IN (select material_id
                                            from mat
                                      inner join con on con.content_id = mat.content_id
                                      inner join con_groups on con_groups.content_id = con.content_id
                                           where con_groups.content_group_id = 10)) x
LEFT OUTER JOIN mat sp_m ON sp_m.material_id = x.special_mat_primary_key;

Дайте мне знать, что вы думаете.

...