Select 行在某些相关行中具有大于零的特定列

Select rows with a specific column greater than zero in some related rows

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

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,table,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 中 运行 此查询的最有效方式。

澄清拼写错误后,是的,查询应该按照您的描述执行。

这是等价的并且更快一点:

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);

相关:

  • Using a column in sql join without adding it to group by clause

优化读取性能

如果您需要优化此特定查询的性能并且有多个不合格的行(不是 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 运行 并且 table 上的写入负载不是太大,您应该会看到该索引上的仅索引扫描。

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

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);

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