Не знаю, как написать сложный запрос SQL - PullRequest
2 голосов
/ 20 сентября 2009

У меня следующая структура БД:

Файл, Пользователь, FileRevision (имеет внешний ключ к Файлу и соединение многие-2-многие через промежуточную таблицу с Пользователем).

Я хочу получить все FileRevision-ы, которые:

  1. являются новейшими / самыми свежими в своих соответствующих файлах,
  2. имеют ссылку многие-2-многие на пользователя, который выполняет поиск (проверку прав доступа).

Я узнал, что могу сделать (1), выполнив что-то вроде:

SELECT created_on, file_id FROM FileRevision
WHERE created_on = (SELECT MAX(created_on) FROM FileRevision
                    WHERE filed_id = file_id)

но я понятия не имею, как одновременно выполнять проверку разрешения m2m

Ответы [ 3 ]

2 голосов
/ 20 сентября 2009

Это разновидность проблемы «наибольший n на группу». Вот как я решаю это без подзапроса и без GROUP BY:

SELECT f1.*
FROM Permissions p -- this is the many-to-many table
JOIN FileRevision f1
  ON (f1.file_id = p.file_id)
LEFT OUTER JOIN FileRevision f2 
  ON (f2.file_id = p.file_id AND f1.created_on < f2.created_on)
WHERE p.user_id = ? AND f2.file_id IS NULL;

Замените желаемый идентификатор пользователя на "?".

1 голос
/ 20 сентября 2009

Чтобы проверить разрешения, вам нужно убедиться, что в другой таблице разрешений многие-2-многие есть запись для пользователя, запрашивающего файлы. Так что добавьте предложение И / ИЛИ Существует ... Если вы хотите (как я подозреваю) только последнюю ревизию, к которой запрашивающий имеет доступ, используйте AND.

Если вы хотите И последнюю версию, и записи, к которым имеет доступ запрашивающая сторона, используйте ИЛИ.

SELECT created_on, file_id 
FROM FileRevision r
WHERE created_on = 
    (SELECT MAX(created_on) 
     FROM FileRevision                    
     WHERE file_id = r.file_id)
  And Exists       --  Change 'And' to 'Or if you want both
     (Select * From M2MIntermediatePermissionsTable
      Where File_Id = r.File_Id
          And userId = ?)
1 голос
/ 20 сентября 2009

Просто добавьте это к вашему запросу:

UNION
SELECT created_on, file_id
FROM FileRevision fr
WHERE fr.user_id = ?

Заменить? с любым значением, которое вы хотите, основываясь на проверке вашего разрешения.

Кроме того, если вы замените свой запрос на:

SELECT created_on, file_id 
FROM FileRevision fr 
  JOIN 
  (
    SELECT file_id, MAX(created_on) as latestDate 
    FROM FileRevision 
    GROUP BY file_id
  ) latest ON latest.file_id = fr.file_id 
           AND latest.latestDate = fr.created_on

Вы избежите коррелированного (повторяющегося) подзапроса.

...