【问题标题】:SQL Server Create View from Two TablesSQL Server 从两个表创建视图
【发布时间】:2018-07-24 05:50:25
【问题描述】:

我在一个跟踪社交网络的 SQL Server 数据库中有两个表。首先是friends表,看起来像

userId | friendId | acceptDate
==============================
   1   |     8    | 2018-01-20
   8   |     12   | 2017-11-20
   12  |     1    | 2017-12-18

所以每一对都是唯一的组合,顺序只是由哪个用户发起连接来决定的。

第二张表是有用户信息的表

userId | name | email | ...
   1   | John  | john@example.com  | ...
   2   | Bill  | bill@example.com  | ...
   3   | Cathy | cathy@example.com | ...

我想创建一个视图,在该视图中,我可以通过最少的服务器端处理轻松获取特定用户的朋友所需的数据。所以本质上我想创建一个数据看起来像的视图:

userId | friendID | friendName | friendEmail | acceptDate | ....
   1   |     8    |  8's Name  |  8's Email  | 2018-01-20 |...
   1   |    12    |  12's Name |  12's Email | 2017-12-18 |...
   8   |    12    |  12's Name |  12's Email | 2017-11-20 |...
   8   |     1    |  1's Name  |  1's Email  | 2018-01-20 |...
  12   |     1    |  1's Name  |  1's Email  | 2017-12-18 |...
  12   |     8    |  8's Name  |  8's Email  | 2017-11-20 |...

基本上,它将从朋友表中存在的每个友谊对创建两行(一个按现有顺序,一个翻转),并将加入用户表中的朋友信息。这样,我可以简单地查询视图以找到我所有特定用户的朋友,它只会返回该用户的朋友的行及其信息,我无需进行任何处理来整理。

任何帮助将不胜感激。

谢谢!

【问题讨论】:

  • 您的桌子设计不是最理想的,但它可以工作。你试过什么?在我看来,您需要在 userID 或friendID 上使用左连接到您的另一个表。
  • 好吧,也许不是左连接,因为这会返回没有朋友的用户,这不是问题中想要的结果。
  • @TabAlleman 确实如此。这个查询之所以这么难,是因为数据结构设计得不好。当您正确设计数据时,很容易检索信息。但是,当您的设计不好时,使用起来会很痛苦。
  • 非常感谢大家帮助我!该数据库应该如何设计以使事情变得更容易?我很想听听你们的任何建议,看看我能不能做些什么。 @SeanLange
  • 我更多地来自编程背景,因此结构化 SQL 查询与在 python 或 php 中处理数据需要一些不同的思维方式。我尝试了几种类型的连接,但下面使用带有“on”/“or”部分的内部连接的答案似乎已经成功了。我试图在我的帖子中尽可能清楚,但不确定为什么我在那里得到了反对票,但是任何关于这方面的提示都会对以后的帖子有用。再次感谢!

标签: sql sql-server tsql join


【解决方案1】:

这是一种可以通过 JOIN 完成的方法:

SELECT u.UserID, fi.UserID AS FriendID, fi.Name, fi.email, f.acceptdate
FROM UserInfo u
INNER JOIN Friends f
  ON u.UserID=f.UserID
  OR u.UserID=f.FriendID
INNER JOIN UserInfo fi
  ON (fi.UserID=f.UserID AND u.UserID=f.FriendID)
  OR (fi.UserID=f.FriendID AND u.UserID=f.UserID)
ORDER BY u.UserID, fi.UserID

【讨论】:

  • 我不太确定我对我们 4 个人用不合逻辑的设计回答这个问题的感觉如何,而不是详细解释设计的缺陷并向操作展示建模的正确方法...
  • 我认为这是一种克服不良设计的练习。一些开发人员无法重新定义数据库设计。但是,如果至少有一个答案显示了针对同一目标的更好设计,那肯定会为网站增加价值。
  • 非常感谢大家帮助我!该数据库应该如何设计以使事情变得更容易?我很想听听你们的任何建议,看看我能不能做些什么。 @TabAlleman
【解决方案2】:

因为您必须切换前两列中的所有数据,所以您需要将数据量翻倍。这可能是使用 UNION ALL 最简单的方法。这样的事情应该很接近了。

select *
from
(
    select UserID
        , FriendID
        , FriendName = sot.name
    from SomeTable st
    join SomeOtherTable sot on sot.UserID = st.UserID

    UNION ALL

    select FriendID
        , UserID
        , FriendName = sot.name
    from SomeTable st
    join SomeOtherTable sot on sot.UserID = st.FriendID
) x
order by x.UserID
    , x.FriendID

【讨论】:

    【解决方案3】:
    -- Friends I accepted 
    select userid, f.userId friendID, f.name friendName, f.email friendEmail, friends.acceptDate
    from users inner join friends on users.userId = friends.userId inner join users f on friends.friendId = f.Userid
    
    union all
    -- friends who accepted me. 
    select userid, f.userId friendID, f.name friendName, f.email friendEmail, friends.acceptDate
    from users inner join friends on users.userId = friends.friendID inner join users f on friends.userid = f.Userid
    

    【讨论】:

      【解决方案4】:

      这是一个工作示例:

      编辑,我已经添加了来自用户 ID 的电子邮件,并添加了 union all 以支持 ops 之心,快乐 v-day。

      declare @user as table (
          userID       int identity(1,1) not null primary key clustered
      ,   Name_        nvarchar(255) not null
      ,   EmailAddress nvarchar(255) not null
      );
      
      declare @duo as table (
          duoID   int identity(1,1) not null primary key clustered 
      ,   userID  int not null
      ,   loserID int not null
      ,   LoveDate date not null
      );
      
      insert into @user (name_, EmailAddress)
      
      select 'bob', 'bob@example.com' union all
      select 'tom', 'tom@example.com' union all
      select 'nick', 'nick@example.com' union all
      select 'Random', 'awesomesauce@example.com';
      
      insert into @duo (userid, loserid, LoveDate)
      select 1, 2, '2018-01-14' union all
      select 1, 3, '2018-02-14' union all
      select 1, 4, '2018-01-15' union all
      select 2, 3, '2018-01-14' union all
      select 2, 4, '2018-01-18' union all
      select 3, 4, '2018-01-13';
      
      
      select a.UserID
           , a.Name_ Person
           , a.EmailAddress
           , c.userID LoserID
           , c.Name_ Loser
           , c.EmailAddress 'Loser''s Email'
           , b.LoveDate
        from @user a
        join @duo b
          on a.userid = b.userid
        join @user c
          on b.loserid = c.userid
      
      union all
      
      select c.userID 
           , c.Name_ Person
           , c.EmailAddress
           , a.UserID LoserID
           , a.Name_ Loser
           , a.EmailAddress 'Loser''s Email'
           , b.LoveDate
        from @user a
        join @duo b
          on a.userid = b.userid
        join @user c
          on b.loserid = c.userid
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-30
        • 2011-11-03
        相关资源
        最近更新 更多