【问题标题】:Select all records of one table that contain two records in another with certain id选择一个表的所有记录,其中包含另一个具有特定 id 的两条记录
【发布时间】:2020-07-03 13:49:01
【问题描述】:

我有两个 1:m 关系表。需要选择哪些 People 记录在 Actions 表中同时具有 id 1 和 2 的记录

People
+----+------+--------------+
| id | name | phone_number |
+----+------+--------------+
| 1  | John | 111111111111 |
+----+------+--------------+
| 3  | Jane | 222222222222 |
+----+------+--------------+
| 4  | Jack | 333333333333 |
+----+------+--------------+

Action
+----+------+------------+
| id | PplId| ActionId   |
+----+------+------------+
| 1  |   1  |      1     |
+----+------+------------+
| 2  |   1  |      2     |
+----+------+------------+
| 3  |   2  |      1     |
+----+------+------------+
| 4  |   4  |      2     |
+----+------+------------+

Output
+----+------+--------------+----------
|PplId| name | Phone       |ActionId |
+-----+------+-------------+----+-----
| 1   | John | 111111111111|   1     |
+-----+------+-------------+----+-----
| 1   | John | 111111111111|   2     |
+-----+------+-------------+----+-----

   

返回具有 Actionid 1 和 Action id 2 的人员的记录(在 Actions 中有记录)。

【问题讨论】:

    标签: sql sql-server join left-join


    【解决方案1】:

    窗口函数是一种方法。假设一个人的动作不重复:

    select pa.*
    from (select p.*, a.action, count(*) over (partition by p.id) as num_actions
          from people p join
               action a
               on p.id = a.pplid
          where a.action in (1, 2)
         ) pa
    where num_actions = 2;
    

    在我看来,获得包含动作细节的两行似乎是多余的——您已经知道这些动作。如果你只想要人,那么exists就会出现:

    select p.*
    from people p
    where exists (select 1 from actions where a.pplid = p.id and a.action = 1) and
          exists (select 1 from actions where a.pplid = p.id and a.action = 2);
    

    使用正确的索引 (actions(pplid, action)),我希望两个 existsgroup by 快。

    【讨论】:

      【解决方案2】:

      使用子查询和连接试试下面的查询

      select a.Pplid, name, phone, actionid from (
      select a.pplid as Pplid, name, phone_number as phone
      from People P
      join Action A on a.pplid= p.id
      group by a.pplid, name, phone_number
      having count(*)>1 )P
      join Action A on a.Pplid= p.Pplid
      

      【讨论】:

        【解决方案3】:

        试试这样的

        IF OBJECT_ID('tempdb..#People') IS NOT NULL DROP TABLE #People
        CREATE TABLE #People (id INT, name VARCHAR(255), phone_number VARCHAR(50))
        INSERT #People
        SELECT 1, 'John', '111111111111' UNION ALL
        SELECT 3, 'Jane', '222222222222' UNION ALL
        SELECT 4, 'Jack', '333333333333' 
        IF OBJECT_ID('tempdb..#Action') IS NOT NULL DROP TABLE #Action
        CREATE TABLE #Action (id INT, PplId INT, ActionId INT)
        INSERT #Action
        SELECT 1, 1, 1 UNION ALL
        SELECT 2, 1, 2 UNION ALL
        SELECT 3, 2, 1 UNION ALL
        SELECT 4, 4, 2
        GO
        
        SELECT      p.ID                AS PplId
                    , p.name
                    , p.phone_number    AS Phone
                    , a.ActionId
        FROM        #People p
        JOIN        #Action a
        ON          p.ID = a.PplId
        WHERE       p.ID IN (   SELECT      PplId 
                                FROM        #Action
                                WHERE       ActionId IN (1, 2) 
                                GROUP BY    PplId
                                HAVING      COUNT(*) = 2    )
                    AND a.ActionId IN (1, 2)
        GO
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-03-12
          • 1970-01-01
          • 1970-01-01
          • 2016-05-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-16
          相关资源
          最近更新 更多