Задача сделать 1 большой запрос из множества маленьких - PullRequest
1 голос
/ 01 августа 2011

У меня проблема, которую я легко решаю с помощью php и некоторых запросов, но я хотел сделать один большой запрос (по крайней мере, если он быстрее, чем, я полагаю, должен быть).

Итак, у меня есть 3 таблицы, и позвольте немного упростить их:

topic, который имеет 3 столбца

  • ID
  • user_id
  • видимость

access, который имеет 2 столбца

  • topic_id
  • user_id

friendship, который имеет 2 столбца

  • user_id
  • friend_id

Что я хочу сделать, так это если пользователь (мы называем его watch_id) пытается просмотреть эту тему. Я хочу вернуть тему, если ему разрешено смотреть, а если нет, ничего не вернуть. Ему разрешено смотреть, если хоть что-то из этого верно :

  • watch_id == user_id
  • видимость == 3
  • visiblity == 2 && Таблица дружбы возвращает строку, когда Friends.user_id = topic.user_id && Friends.friend_id == watch_id
  • visibility == 1 && таблица доступа возвращает строку, когда access.topic_id = topic.id && access.user_id == watch_id

Как вы можете видеть, это не очень сложно сделать с php и кучей запросов, но только в sql я не могу понять это. Я пробовал соединения, дела и прочее, но логика никогда не складывается. (

Так вы, ребята, можете мне помочь? Или я застрял с php и большим количеством запросов?

Редактировать: Хм, похоже, я не очень хорошо себя прояснил, мой плохой! Ему разрешено наблюдать, если какое-либо из этих требований верно. Так как это так, я иду с ответом левого соединения, который было проще всего расширить. Спасибо всем!

Ответы [ 4 ]

3 голосов
/ 01 августа 2011

Вы должны иметь возможность создавать левые объединения для таблиц дружбы и доступа, чтобы сами объединения не ограничивали результат:

select something
from topic
left join friendship on friendship.user_id = topic.user_id && friendship.friend_id == watch_id
left join access on access.topic_id = topic.id && access.user_id == watch_id
where
  watch_id == topic.user_id or
  topic.visibility == 3 or
  (topic.visiblity == 2 and friendship.user_id is not null) or
  (visibility == 1 && access.topic_id is not null)
0 голосов
/ 01 августа 2011

Попробуйте подзапросы:

select topic.* from topic
where (topic.user_id = watch_id and visibility=3) or 
      (topic.user_id = watch_id and visibility=2 and (select count(*) from friendship where friendship.user_id = topic.user_id and friendship_id = watch_id) > 0) or
      (topic.user_id = watch_id and visibility=1 and (select count(*) from access where access.topic_id = topic.id and access.user_id = watch_id) > 0)

Это решение позволяет использовать одну тему, даже если имеется несколько записей о дружбе или доступе. Глядя на ваш вопрос, я сделал предположение, что topic.user_id должен равняться watch_id для всех трех, но я могу ошибаться.

Однако, если между тремя таблицами существует только отношение один-к-одному, то левосторонние соединения - это путь.

0 голосов
/ 01 августа 2011

Если у вас есть три отдельных запроса, которые возвращают то, что вам нужно, вы можете рассмотреть возможность объединения трех наборов результатов, чтобы получить нужные темы.

В основном следующее должно вернуть вам список всех тем, которые пользователь может смотреть.

select t.topic_id
from   topic as t
where  t.user_id = watch_id
and    t.visibility = 3
  union
select t.topic_id
from   topic as t
inner join friendship as f
on     f.user_id = t.user_id
where  f.friend_id = watch_id
and    t.visibility = 2
  union
select t.topic_id
from   topic as t
inner join access as a
on     a.topic_id = t.id
where  a.user_id = watch_id
and    t.visibility = 1

Вы должны быть в состоянии использовать это, чтобы получить то, что вам нужно.

Если вам нужна процедура или функция, которая может подтвердить возможность просмотра данного topic_id, то вы можете проверить, содержится ли topic_id в указанном выше наборе результатов

0 голосов
/ 01 августа 2011

Это может быть возможно с одним запросом, но проще всего будет использовать UNION для объединения результатов ваших различных требований.

SELECT t.*
FROM   topic AS t
WHERE  t.user_id = @watch_id AND t.visibility = 3
UNION ALL
SELECT t.*
FROM   topic AS t
       INNER JOIN friendship AS f ON f.user_id = t.user_id
WHERE  f.friend_id_id = @watch_id AND t.visibility = 2
UNION ALL
SELECT t.*
FROM   topic AS t
       INNER JOIN access AS a ON a.topic_id = t.id
WHERE  a.user_id = @watch_id AND t.visibility = 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...