2016-08-12 2 views
2

Я хочу создать условное соединение по таблицам.Условное соединение на таблицах

Я уже проверил here. Но я также читал, что OUTER JOIN может быть не лучшим способом (с точки зрения производительности), так как полное сканирование таблицы все еще происходит? А также, по-видимому, есть разница во мнениях по эффективности использования UNION.

Каким образом я могу условно присоединиться к таблицам на основе моих требований ниже? пс. Если это требует ваше решение, я могу реализовать это как хранимую процедуру, чтобы создать еще более динамический SQL.

Для всех строк, где userfavorites.objecttype = 100, на основе значения photos.objecttype Я хочу присоединиться к другой таблице. Если значение objecttype равно 1, я хочу присоединиться к [locations], если значение равно 2 Я хочу присоединиться к [persons].

Как выход я хочу следующие столбцы:
photos.title, photos.locpath, (persons.title или locations.title), (persons.friendlyurl или locations.friendlyurl), userfavorites.objectid, userfavorites.objecttype

теперь у меня есть это, чтобы получить строки для одного пользователя:

SELECT * FROM userfavorites uf 
INNER JOIN photos vp ON uf.objectid=vp.id 
WHERE uf.objecttype=100 AND uf.userid='32DD30EB-1691-457B-9FF5-FC41D687E579' 

DDL и вставить операторы:

CREATE TABLE [dbo].[photos](
    [id] [int] NOT NULL, 
    [objectid] [int] NOT NULL, 
    [locpath] [nvarchar](150) NOT NULL, 
    [objecttype] [tinyint] NOT NULL, 
    [title] [nvarchar](50) NULL) ON [PRIMARY] 

CREATE TABLE [dbo].[userfavorites](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [userid] [uniqueidentifier] NOT NULL, 
    [objectid] [int] NOT NULL, 
    [objecttype] [tinyint] NOT NULL CONSTRAINT [DF_userfavorites_objecttype] DEFAULT ((0)), 
CONSTRAINT [PK_userfavorites] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


CREATE TABLE [dbo].[persons](
    [id] [int] NOT NULL, 
    [title] [nvarchar](80) NOT NULL, 
    [friendlyurl] [nvarchar](80) NULL, 
CONSTRAINT [PK_persons_1] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

CREATE TABLE [dbo].[locations](
    [id] [int] NOT NULL, 
    [title] [nvarchar](80) NOT NULL, 
    [friendlyurl] [nvarchar](80) NULL, 
CONSTRAINT [PK_locations_1] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 




USE [tt] 
SET IDENTITY_INSERT [dbo].[userfavorites] ON 

INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'32dd30eb-1691-457b-9ff5-fc41d687e579', 41029, 100) 
INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'32dd30eb-1691-457b-9ff5-fc41d687e579', 41030, 100) 
INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'32dd30eb-1691-457b-9ff5-fc41d687e579', 40880, 100) 
INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'32dd30eb-1691-457b-9ff5-fc41d687e579', 40885, 100) 
INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'32dd30eb-1691-457b-9ff5-fc41d687e579', 40882, 100) 
INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'32dd30eb-1691-457b-9ff5-fc41d687e579', 4067, 100) 
INSERT [dbo].[userfavorites] ([userid], [objectid], [objecttype]) VALUES (N'BC5EB8A7-FEC2-4932-9C67-AE5A35C4012B', 4067, 100) 
SET IDENTITY_INSERT [dbo].[userfavorites] OFF 

INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (41029, 1, 1, N'hiltonsky.jpg', N'Overview') 
INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (41030, 1, 1, N'pool.jpg', N'Swimming') 
INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (40880, 2, 1, N'entrance.jpg', N'Lobby Entrance') 
INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (40885, 2, 1, N'room.jpg', N'Room view') 
INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (40882, 1, 2, N'zuck.jpg', N'Mark') 
INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (4067, 2, 2, N'gates.jpg', N'Bill') 
INSERT [dbo].[photos] ([id], [objectid], [objecttype], [locpath], [title]) VALUES (50673, 3, 2, N'musk.jpg', N'Elon') 

INSERT [dbo].[locations] ([id], [title], [friendlyurl]) VALUES (1, N'Hilton Hotel', 'hilton-hotel') 
INSERT [dbo].[locations] ([id], [title], [friendlyurl]) VALUES (2, N'Marriot Hotel', 'marriot-hotel') 


INSERT [dbo].[persons] ([id], [title], [friendlyurl]) VALUES (1, N'Mark Zuckerberg', 'mark-zuckerberg') 
INSERT [dbo].[persons] ([id], [title], [friendlyurl]) VALUES (2, N'Bill Gates', 'bill-gates') 
INSERT [dbo].[persons] ([id], [title], [friendlyurl]) VALUES (3, N'Elon Musk', 'elon-musk') 

Так что для идентификатора пользователя 32dd30eb-1691-457b-9ff5-fc41d687e579, результат будет:

+----------------+---------------+-----------------+-----------------+----------+------------+ 
| phototitle | locpath |  title  | friendlyurl | objectid | objecttype | 
+----------------+---------------+-----------------+-----------------+----------+------------+ 
| Overview  | hiltonsky.jpg | Hilton Hotel | hilton-hotel |  1 |   1 | 
| Swimming  | pool.jpg  | Hilton Hotel | hilton-hotel |  1 |   1 | 
| Lobby Entrance | entrance.jpg | Marriot Hotel | marriot-hotel |  2 |   1 | 
| Room view  | room.jpg  | Marriot Hotel | marriot-hotel |  2 |   1 | 
| Mark   | zuck.jpg  | Mark Zuckerberg | mark-zuckerberg |  1 |   2 | 
| Bill   | gates.jpg  | Bill Gates  | bill-gates  |  2 |   2 | 
+----------------+---------------+-----------------+-----------------+----------+------------+ 
+0

Вы должны исправить форматирование вашего запроса, особенно на уровне репутации. Ваш запрос выглядит хорошо для меня, без дополнительной информации. –

+0

@TimBiegeleisen: Благодарим вас за отзыв! Что именно не так с форматированием запроса? Я думал, что я уже обозначил его как блок кода. И как вы могли так быстро форматировать мои желаемые результаты запроса? Спасибо (даже на уровне репутации ... до сих пор учась :) – Flo

ответ

4

Там нет ничего плохого с внешними соединениями, и, кажется, прямым подходом к этой проблеме. Независимо от того, будет ли использоваться полное сканирование таблицы, зависит от СУБД; он будет решать для обеспечения быстрого доступа к данным в зависимости от того, что может быть.

SELECT 
    vp.phototitle, 
    vp.locpath, 
    coalesce(l.title, p.title) as title, 
    coalesce(l.friendlyurl, p.friendlyurl) as friendlyurl, 
    uf.objectid, 
    uf.objecttype 
FROM userfavorites uf 
INNER JOIN photos vp ON uf.objectid = vp.id 
LEFT JOIN locations l on vp.objecttype= 1 and vp.objectid = l.id 
LEFT JOIN persons p on vp.objecttype= 2 and vp.objectid = p.id 
WHERE uf.objecttype = 100 AND uf.userid = '32DD30EB-1691-457B-9FF5-FC41D687E579'; 

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

+1

Не присоединяйте отдельные объекты в одной таблице, когда-либо. Если нет никакой разницы между отслеживанием людей на фотографии и отслеживанием местоположения на фотографии, то они являются * одним и тем же объектом *, и для их отличия не следует использовать флаг. В противном случае должен быть какой-то атрибут, который их отличает. Например, люди могут быть мужчинами или женщинами (или, возможно, другими полами); в то время как места могут быть внутренними или наружными, иностранными или домашними, горячими или дождливыми ... –

+0

@ Ross Presser: флаг * - это атрибут, который их отличает. Как еще вы выбрали бы все фотографии людей, когда люди и места находятся в одной таблице? Но да, может быть больше атрибутов, а затем решать, иметь ли одну таблицу с одним или другим набором атрибутов, заполненными или двумя таблицами, каждый со своими атрибутами. –

0
with cte as 
(SELECT * FROM userfavorites uf 
    INNER JOIN photos vp ON uf.objectid=vp.id 
    WHERE uf.objecttype=100 AND uf.userid='32DD30EB-1691-457B-9FF5-FC41D687E579') 
SELECT * 
from cte 
JOIN locations on cte.objecttype = 1 and cte.objectid = locations.id 
union all 
SELECT * 
from cte 
JOIN persons on cte.objecttype = 2 and cte.objectid = persons.id 
Смежные вопросы