【问题标题】:How to find distinct users in multiple tables如何在多个表中找到不同的用户
【发布时间】:2016-01-19 14:24:09
【问题描述】:

我有一个名为 users 的表,其中包含用户 ID,以及一些表,如 cloud_storage_acloud_storage_bcloud_storage_c。如果cloud_storage_a 中存在用户,则表示他们已连接到云存储 a。用户也可以存在于许多云存储中。这是一个例子:

users表:

user_id | address      | name
-------------------------------
123     | 23 Oak Ave   | Melissa
333     | 18 Robson Rd | Steve
421     | 95 Ottawa St | Helen
555     | 12 Highland  | Amit
192     | 39 Anchor Rd | Oliver

cloud_storage_a:

user_id
-------
 421
 333

cloud_storage_b:

user_id
-------
 555

cloud_storage_c:

user_id
-------
 192
 555

等等

我想创建一个查询来获取连接到任何云存储上的所有用户。所以对于这个例子,应该返回用户421, 333, 555, 192。我猜这是某种加入,但我不确定是哪一种。

【问题讨论】:

    标签: sql postgresql join distinct exists


    【解决方案1】:

    你很接近。您希望使用将记录集/表堆叠在一起的 UNION,而不是基于键将表彼此合并的 JOIN。

    SELECT user_id FROM cloud_storage_a
    UNION
    SELECT user_id FROM cloud_storage_b
    UNION
    SELECT user_id FROM cloud_storage_c
    

    在此处使用关键字 UNION 将为您提供所有三个表中不同的 user_id。如果您将其切换为UNION ALL,您将不再获得 Distinct,这在其他情况下具有优势(显然不在这里)。

    编辑添加:

    如果你想引入用户地址,你可以使用这个东西作为子查询并加入你的用户表:

    SELECT
        subunion.user_id
        user.address
    FROM
        user
        INNER JOIN
            (
                SELECT user_id FROM cloud_storage_a
                UNION
                SELECT user_id FROM cloud_storage_b
                UNION
                SELECT user_id FROM cloud_storage_c
            ) subunion ON
                user.user_id = subunion.user_id
    

    随着您添加更多 cloud_storage_N 表,该联合将需要增长。总而言之,这不是一个伟大的数据库设计。您最好创建一个cloud_storage 表并有一个字段来描述它是abc、...、N

    那么您的 UNION 查询将只是 SELECT DISTINCT user_id FROM cloud_storage; 并且您永远不需要再次编辑它。

    【讨论】:

    • 如何包含 users 表? (即如果我想在结果中包含 users.address 怎么办?)
    • 我在答案中添加了一个额外的查询,它将从 users 表中引入地址。
    • 如果我有一个 cloud_storage 表,我将如何标记用户是否属于其中的许多表? (即用户可以连接到 a、b 和 c)
    • 那么您将在该用户的单个cloud_storage 表中拥有三个记录。您的cloud_storage 表将有两个字段:user_idcloud_table_name。如果user_id 555 属于所有三个,您的值将是:555, a555, b555, c。这里的好处是,当您添加新的cloud_table_names 时,您只需要一个新记录,而不是一个新表:555, d
    【解决方案2】:

    您需要以这种方式加入未知(?)数量的表cloud_storage_X

    您最好将架构更改为以下内容:

    存储:

    user_id cloud
    ------- -----
     421     a
     333     a
     555     b
     192     c
     555     c
    

    那么查询就这么简单:

    select distinct user_id
    from   storage;
    

    【讨论】:

      【解决方案3】:
      select u.* from users u,
       cloud_storage_a csa,
       cloud_storage_b csb,
       cloud_storage_c csc 
      where u.user_id = csa.user_id or u.user_id = csb.user_id or u.user_id = csc.user_id
      

      您应该简化架构以处理此类查询。

      【讨论】:

      • 这可能会为每个用户返回多行,并且比其他可能的查询样式更昂贵。
      【解决方案4】:

      要从您的users 表中为所有(不同的)合格用户获取列:

      SELECT * -- or whatever you need
      FROM   users u
      WHERE  EXISTS (SELECT 1 FROM cloud_storage_a WHERE user_id = u.user_id) OR
             EXISTS (SELECT 1 FROM cloud_storage_b WHERE user_id = u.user_id) OR
             EXISTS (SELECT 1 FROM cloud_storage_c WHERE user_id = u.user_id);
      

      仅获取所有user_id 而没有别的,@JNevill's UNION query 看起来不错。您可以将此结果加入users 以达到相同的效果:

      SELECT u.* -- or whatever you need
      FROM   users u
      JOIN  (
         SELECT user_id FROM cloud_storage_a
         UNION
         SELECT user_id FROM cloud_storage_b
         UNION
         SELECT user_id FROM cloud_storage_c
         ) c USING user_id);
      

      但这可能会更慢。

      【讨论】:

        猜你喜欢
        • 2018-05-04
        • 2021-01-17
        • 2016-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-05
        • 1970-01-01
        相关资源
        最近更新 更多