如何在 PostgreSQL 中正确使用 LIMIT 使每个 ID 只查询一行

How to use LIMIT in PostgreSQL correctly to only query one row per ID

我有一个查询,用户输入名为 {placeholders} 的股票列表,该列表存储在 python 变量中。查询将从 t1 中提取 9 列,从 t2.

中提取 1 列
f''' SELECT t1.id, cast(t1.enterprisevalue as money), ROUND(t1.enterprise_value_revenue, 2),
      ROUND(t1.revenuepershare, 2), 
      ROUND(t1.debt_to_equity, 2), 
      ROUND(t1.profitmargin, 2), 
      ROUND(t1.price_to_sales, 2), 
      ROUND(t1.price_to_book, 2), 
      ROUND(t1.put_call_ratio, 2), 
      t2.employees, 
      cast(ROUND(t1.revenue_per_employee, 2) as money)
FROM 
      security_advanced_stats as t1 
LEFT JOIN security_stats as t2 USING (id)
WHERE id IN ({placeholders})
ORDER by id LIMIT 1;
''' 

我想要 {placeholders} 中的每个股票代码一行,这就是我在这里使用 LIMIT 的原因。但是,语法错误,查询现在将 {placeholders} 限制为仅列表中的第一个符号。我的查询输出仅显示一个股票代码的数据,而不显示 {placeholders}

中的其他股票代码的数据

如果我去掉 LIMIT 命令,那么当我只是在寻找我的股票的最新记录时,我会得到数据库中的所有行(我将其标记为 id).

这是当我去掉限制时发生的情况,注意有两个符号 EXPD 和 VFC,但它们彼此具有相同数据的所有其他条目。

在上述情况下,我只想要 EXPD 和 VFC 的最新行。

如何解决我的查询?

您可以将 first_valuegroup by 一起使用:

SELECT t1.id, 
    cast(first_value(t1.enterprisevalue as money) over w), 
    round(first_value(t1.enterprise_value_revenue) over w, 2),
    ...
from security_advanced_stats as t1 
left join security_stats as t2 USING (id)
where id in ({placeholders})
group by t1.id
window w as (partition by t1.id);

DISTINCT ON 功能非常适合这一点。基本上,您可以选择不想重复的字段,并且每次排序只获取第一行。 (我假设您有某种 timestamp 列,因此我们可以获得每个 ID 的最新行。)

SELECT DISTINCT ON (t1.id)
    t1.id, 
    cast(t1.enterprisevalue as money), 
    ROUND(t1.enterprise_value_revenue, 2),
    ROUND(t1.revenuepershare, 2), 
    ROUND(t1.debt_to_equity, 2), 
    ROUND(t1.profitmargin, 2), 
    ROUND(t1.price_to_sales, 2), 
    ROUND(t1.price_to_book, 2), 
    ROUND(t1.put_call_ratio, 2), 
    t2.employees, 
    cast(ROUND(t1.revenue_per_employee, 2) as money)
FROM security_advanced_stats as t1 
LEFT JOIN security_stats as t2 USING (id)
WHERE id IN ({placeholders})
ORDER by id, timestamp DESC;