如何在 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_value
与 group 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;
我有一个查询,用户输入名为 {placeholders}
的股票列表,该列表存储在 python 变量中。查询将从 t1
中提取 9 列,从 t2
.
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_value
与 group 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;