【问题标题】:Select rows with a specific column greater than zero in some related rows在某些相关行中选择特定列大于零的行
【发布时间】:2018-06-10 12:29:54
【问题描述】:

我在 Postgres 9.5 数据库中有以下表:

product_days

Column     | Type    | Modifiers
-----------+---------+----------------------------------------------
id         | integer | not null default nextval('product_days_id_seq'::regclass)
days_id    | integer |
product_id | integer |
available  | integer | 
price      | integer |
 Indexes:
"pk_product_days" PRIMARY KEY, btree (id)
"idx_product_days" btree (days_id)
"idx_product_days_0" btree (product_id)
Foreign-key constraints:
   "product_days_days_id_fkey" FOREIGN KEY (days_id) REFERENCES days(id)

product

 Column         |            Type             |                       Modifiers
----------------+-----------------------------+-----------------------------------------------------
id              | integer                     | not null default nextval('product_id_seq'::regclass)
name            | character varying(100)      |
number_of_items | integer                     |
created_at      | timestamp without time zone | default now()
updated_at      | timestamp without time zone | default now()
total_number    | integer                     |
 Indexes:
    "pk_product" PRIMARY KEY, btree (id)

product_days.product_id 是引用product 表的外键,available 表示每天可用的产品数量。

我想获得在某些特定日期 (days_id between 5 and 10) 可用的所有产品 (available > 0)。这些天所有都应该可以使用它们。

目前我正在尝试使用以下查询获取结果,但我不确定它是否正确或者这是最有效的方法:

select product.id as p_id, product.name as p_name, product.number_of_items as items
from product_days join product ON product_days.product_id = product.id
WHERE product_days.available > 0
AND  prodcut_days.days_id between 5 and 10
group by product.id
HAVING count(*) > 5;

输出应该是这样的:

 p_id  | p_name    | items
-------+-----------+-------
 1     | product_1 | 4
 2     | product_2 | 13

我需要在 SQL 或 plpgsql 中运行此查询的最有效方式。

【问题讨论】:

  • 请发布一些示例数据的预期输出
  • @RadimBača 我刚刚编辑了问题,请再次检查
  • 我错过了样本数据
  • 缺少:表定义(显示数据类型和约束)、Postgres 版本、示例数据和您迄今为止尝试过的查询(即使它不起作用)。我想你的意思是你提到“pgpsql”的地方?
  • @ErwinBrandstetter 我已经编辑了这个问题,请您再次检查一下,看看现在是否提供了足够的信息

标签: sql postgresql postgresql-performance relational-division


【解决方案1】:

在澄清错别字后,是的,查询应该按照您的描述进行。

这是等效的,而且速度更快:

SELECT id AS p_id, name AS p_name, number_of_items AS items
FROM  (
   SELECT product_id AS id
   FROM   product_days
   WHERE  available > 0
   AND    days_id BETWEEN 5 AND 10
   GROUP  BY 1
   HAVING count(*) > 5
   ) d
JOIN  product p USING (id);

应该有一个 UNIQUE constraint 强制每个产品和每天最多 1 个条目:

ALTER TABLE product_days ADD CONSTRAINT your_name_here UNIQUE (product_id, days_id);

相关:

优化读取性能

如果您需要优化此特定查询的性能并且有多个不符合条件的行(不是 availableday_id 不匹配),最锋利的武器将是 partial index

CREATE INDEX idx_name_here ON product_days (product_id)
WHERE  available > 0
AND    days_id BETWEEN 5 AND 10;

如果您正在运行 autovacuum 并且表上的写入负载不是太大,您应该会看到此索引上的仅索引扫描。

虽然使用了这个索引(或更通用的索引),但这个查询应该更快,但是:

SELECT id AS p_id, name AS p_name, number_of_items AS items
FROM  (
   SELECT product_id AS id
   FROM   product_days d5
   JOIN   product_days d6  USING (product_id)
   JOIN   product_days d7  USING (product_id)
   JOIN   product_days d8  USING (product_id)
   JOIN   product_days d9  USING (product_id)
   JOIN   product_days d10 USING (product_id)
   WHERE  d5.days_id  = 5  AND d5.available  > 0
   AND    d6.days_id  = 6  AND d6.available  > 0
   AND    d7.days_id  = 7  AND d7.available  > 0
   AND    d8.days_id  = 8  AND d8.available  > 0
   AND    d9.days_id  = 9  AND d9.available  > 0
   AND    d10.days_id = 10 AND d10.available > 0   
   ) d
JOIN  product p USING (id);

因为这是一个以 为核心的案例。见:

【讨论】:

  • 感谢您的帮助,我会试试的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-05
  • 1970-01-01
  • 2015-03-05
  • 2021-12-17
  • 1970-01-01
相关资源
最近更新 更多