Как объединить две таблицы, когда предложение ON является переменным - PullRequest
1 голос
/ 27 марта 2012

Чтобы упростить описание, я буду использовать таблицу участников и почтовую таблицу. Почтовый стол имеет следующую структуру:

-------------------------------
FromMember  int  NOT NULL (FK)
ToMember    int  NOT NULL (FK)
...
-------------------------------

Я хочу написать запрос, который будет возвращать всю почту для определенного участника, будь то FromMember или ToMember. Это просто, просто используйте предложение OR в предложении WHERE.

Но тут все усложняется тем, что я хочу присоединить почтовую таблицу к таблице участников, чтобы получить информацию об элементе для другого члена. Поэтому, если я являюсь FromMember, тогда предложение join для таблицы-члена будет использовать поле ToMember, а если я ToMember, то предложение join будет использовать поле FromMember. По сути, предложение ON должно объединяться с двумя различными полями в зависимости от конкретного условия. Это возможно?

Мое решение до сих пор заключается в использовании UNION ALL следующим образом:

SELECT * FROM mail INNER JOIN member ON mail.ToMember = member.MemberID
WHERE mail.FromMember = @me
UNION ALL
SELECT * FROM mail INNER JOIN member ON mail.FromMember = member.MemberID
WHERE mail.ToMember = @me

Однако я хотел бы поместить этот запрос в представление, потому что набор результатов будет использоваться во многих местах моего кода. Это означает, что мне понадобится параметризованное представление, которое, я думаю, мне нужно реализовать с помощью пользовательской табличной функции.

По сути, я ищу два ответа:
Есть ли лучший способ написать этот запрос вместо UNION ALL?
И должен ли я поместить этот запрос в VIEW или UDF?

Если VIEW является предпочтительным методом, как я могу передать параметр @me в VIEW. Я не могу переместить параметр @me в предложение WHERE, о котором некоторые люди сказали в своих ответах, потому что предложение WHERE зависит от предложения ON. Вытягивание предложения WHERE и последующее ORing не будут возвращать тот же набор результатов, что и вышеупомянутый запрос UNION ALL.

Ответы [ 4 ]

3 голосов
/ 27 марта 2012

1.

SELECT * 
 FROM mail 
  INNER JOIN member 
   ON (mail.FromMember = @me and mail.ToMember = member.MemberID)
    or (mail.ToMember = @me and mail.FromMember = member.MemberID)
  1. Обычно представления выполняются быстрее, чем UDF.
1 голос
/ 27 марта 2012

Я не верю, что T-SQL делает параметризованные представления. Эта функциональность обрабатывается с помощью встроенных табличных функций. Вот функция, которая должна решить вашу проблему:

CREATE FUNCTION fExample_GetRelatedMailMembersForMember
(
    @MemberId INT
)
RETURNS TABLE
AS
RETURN
SELECT
    * -- Replace this with explicit columns
FROM mail M
INNER JOIN member MBR
    ON MBR.MemberID IN (M.FromMember, M.ToMember)
    AND MBR.MemberID <> @MemberId
WHERE M.MemberId = @MemberId
1 голос
/ 27 марта 2012

Вам нужно перевернуть ваш запрос и сделать что-то вроде этого:

SELECT member.* 
FROM member
    LEFT JOIN mail AS ToMail 
        ON ToMail.ToMember = member.MemberID AND ToMail.ToMember = @me
    LEFT JOIN mail AS FromMail 
        ON FromMail.FromMember = member.MemberID AND FromMail.ToMember = @me
WHERE ToMail.ToMember IS NOT NULL OR FromMail.FromMember IS NOT NULL
0 голосов
/ 27 марта 2012

Ваш запрос UNION ALL в порядке. Поместите это в вид почти как;

CREATE VIEW myView AS
SELECT * FROM mail INNER JOIN member ON mail.ToMember = member.MemberID
UNION ALL 
SELECT * FROM mail INNER JOIN member ON mail.FromMember = member.MemberID

Затем, как указано выше @JotaBe, запросите представление, используя предложение WHERE

SELECT * FROM myView WHERE ToMember = @me OR FromMember = @me

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

...