查询多个表,避免联合所有

时间:2016-10-15 05:40:09

标签: sql postgresql

我正在尝试查询以下数据库表:

t_shared_users
user_id
user_category
folder_id
expiry

t_documents
id
folder_id
user_id
user_category
description
created
updated

t_folder
id
type
user_id
user_category
created
updated

我想找到您拥有并拥有共享访问权限的所有文档。即。搜索t_documents中user_id = 1 AND user_category = 100的所有文档,但也包括您在t_shared_users中可以访问的文件夹中的那些文档。以下是我对查询的尝试:

  SELECT
    id,
    folder_id,
    user_id,
    user_category,
    description,
    created,
    updated
  FROM
    t_documents
  WHERE
    user_category = 100
    AND user_id = 1

  UNION ALL

  SELECT
    d.id,
    d.folder_id,
    d.user_id,
    d.user_category,
    d.description,
    d.created,
    d.updated
  FROM
    t_documents d
  JOIN
    t_shared_users s
  ON
    d.folder_id = s.folder_id
  WHERE
    d.user_category = 100
    d.AND user_id = 1

 ORDER BY
   created ASC
 LIMIT
   10

是否有更好/更高效/简洁的方式来编写此查询?以上似乎有点冗长和缓慢。

编辑:

CREATE TABLE t_folder (
  id            SERIAL                   NOT NULL,
  user_category SMALLINT                 NOT NULL,
  user_id       INTEGER                  NOT NULL,
  type          INTEGER                  NOT NULL,
  description   TEXT,
  created       TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  updated       TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY (id)
);

CREATE TABLE t_documents (
  id            BIGSERIAL                NOT NULL,
  folder_id     INTEGER,
  user_category SMALLINT                 NOT NULL,
  user_id       INTEGER                  NOT NULL,
  description   TEXT                     NOT NULL,
  created       TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  updated       TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY (id)
);

CREATE TABLE t_shared_users (
  id            SERIAL,
  folder_id     INTEGER                  NOT NULL,
  user_category INTEGER                  NOT NULL,
  user_id       INTEGER                  NOT NULL,
  expiry        TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY (id)
);

2 个答案:

答案 0 :(得分:1)

这是您的查询:

  SELECT
    id,
    folder_id,
    user_id,
    user_category,
    description,
    created,
    updated
  FROM
    t_documents
  WHERE
    user_category = 100
    AND user_id = 1

  UNION ALL

  SELECT
    d.id,
    d.folder_id,
    d.user_id,
    d.user_category,
    d.description,
    d.created,
    d.updated
  FROM
    t_documents d
  JOIN
    t_shared_users s
  ON
    d.folder_id = s.folder_id
  WHERE
    d.user_category = 100
    AND d.user_id = 1 -- your query actually has a typo here

我对上述查询不了解的原因是您在查询底部对d.user_categoryd.user_idt_documents表)进行过滤。您确定不是s.user_categorys.user_idt_shared_users)吗?如果没有,加入t_shared_users有什么意义?

假设我的查询出错是正确的,这就是我重写它的方法:

select d.*
  from t_documents d
 where d.user_category = 100
   and d.user_id = 1
 union
select d.*
  from t_shared_users s
  join t_documents d
    on d.folder_id = s.folder_id
 where s.user_category = 100
   and s.user_id = 1

请注意,我使用的是union而不是union all,因为我相信在技术上可能会获得可能不需要的重复文档。

另外,正如粗略的近似,这些是我为良好性能定义的索引:

  • t_documents (user_id, user_category)
  • t_documents (folder_id)
  • t_shared_users (user_id, user_category, folder_id)

答案 1 :(得分:-1)

从您提供的查询开始,我会将join替换为left join

select
    d.id,
    d.folder_id,
    d.user_id,
    d.user_category,
    d.description,
    d.created,
    d.updated
from t_documents d
left join t_shared_users s on d.folder_id = s.folder_id
where (d.user_category = 100 and d.user_id = 1)
      or (s.user_category = 100 and s.user_id = 1)

这将为您提供来自t_documents的所有条目,其中user_id = 1和user_category = 100,以及所有具有相同where子句的条目,您可以访问共享文档。