【问题标题】:Conditional join on tables表上的条件连接
【发布时间】:2016-12-19 17:12:21
【问题描述】:

我想在表上创建条件联接。

我已经检查过here。但我也读到OUTER JOIN 可能不是最好的方法(性能方面),因为仍然会进行全表扫描?并且对于使用UNION的性能似乎也存在意见分歧。

我可以根据以下要求有条件地连接表的方式是什么? 附言。如果您的解决方案需要它,我也可以将其作为存储过程来实现,以创建一些更动态的 SQL。

对于 userfavorites.objecttype=100 的所有行,基于 photos.objecttype 的值,我想加入另一个表。 如果objecttype值为1我想加入[locations],如果值为2我想加入[persons]

作为输出,我想要以下列:
photos.title,photos.locpath, (persons.title or locations.title), (persons.friendlyurl or 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')

所以对于用户 ID 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 |
+----------------+---------------+-----------------+-----------------+----------+------------+

【问题讨论】:

  • 您应该修复查询的格式,尤其是在您的代表级别。您的查询对我来说很好,没有更多信息。
  • @TimBiegeleisen:感谢您的反馈!我的查询格式到底出了什么问题?我以为我已经将其标记为代码块了。你怎么能这么快地格式化我想要的查询结果?谢谢(即使在我的代表级别......仍在学习:)

标签: sql-server tsql join conditional


【解决方案1】:

外连接没有任何问题,它似乎是解决问题的直接方法。是否使用全表扫描取决于 DBMS;它将决定以最快的速度访问数据。

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';

但是,如果表中的人员和位置确实非常相似,您可能需要考虑将它们制作为带有标志的单个表,以表明记录是人员还是位置。这将使事情变得更容易并加快访问速度。

【讨论】:

  • 永远不要在同一个表中连接不同的实体。如果在照片中跟踪人物和在照片中跟踪位置之间没有区别,那么它们是同一实体,不应使用标志来区分它们。否则必须有一些属性来区分它们。例如,人们可以是男性或女性(或者可能是其他性别);而地点可以是室内或室外,国外或国内,炎热或下雨......
  • @Ross Presser:标志区分它们的属性。当人物和地点在同一张桌子上时,你还怎么选择人物的所有照片?但是是的,可以有更多的属性,然后是决定是让一个表填充一个或另一组属性,还是两个表,每个表都有自己的属性。
【解决方案2】:
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

【讨论】:

    猜你喜欢
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 2013-09-13
    • 1970-01-01
    • 2020-07-25
    相关资源
    最近更新 更多