我经常需要从结果集中的每个组中选择一些行。
例如,我可能想列出每个客户最近的“n”个最高或最低订单值。
在更复杂的情况下,要列出的行数可能因组而异(由分组/父记录的属性定义)。这部分绝对是可选的/为了额外的学分,而不是为了劝阻人们回答。
在 SQL Server 2005 及更高版本中解决这些类型问题的主要选项是什么?每种方法的主要优点和缺点是什么?
AdventureWorks 示例(为清晰起见,可选)
TransactionHistory,每个产品以从 M 到 R 的字母开头。n每个产品都有历史记录行,其中n是DaysToManufactureProduct 属性的五倍。TransactionDate, .tie-break on TransactionID.我有一个一定很常见的查询模式,但我不知道如何为它编写有效的查询。我想查找与“最近日期不晚于”另一个表的行相对应的表的行。
inventory比如说,我有一张表格,它代表了我在某一天持有的库存。
date | good | quantity
------------------------------
2013-08-09 | egg | 5
2013-08-09 | pear | 7
2013-08-02 | egg | 1
2013-08-02 | pear | 2
Run Code Online (Sandbox Code Playgroud)
和一张表,“价格”说,它保存了某一天的商品价格
date | good | price
--------------------------
2013-08-07 | egg | 120
2013-08-06 | pear | 200
2013-08-01 | egg | 110
2013-07-30 | pear | 220
Run Code Online (Sandbox Code Playgroud)
如何有效地获得库存表每一行的“最新”价格,即
date | pricing date | good | quantity | price
----------------------------------------------------
2013-08-09 | 2013-08-07 | egg | 5 | 120
2013-08-09 …Run Code Online (Sandbox Code Playgroud) postgresql performance greatest-n-per-group query-performance
我有一张这样的表:
ID | Val | Kind
----------------------
1 | 1337 | 2
2 | 1337 | 1
3 | 3 | 4
4 | 3 | 4
Run Code Online (Sandbox Code Playgroud)
我想制作一个SELECT只返回每个 的第一行,按Val排序Kind。
示例输出:
ID | Val | Kind
----------------------
2 | 1337 | 1
3 | 3 | 4
Run Code Online (Sandbox Code Playgroud)
如何构建此查询?
完整问题重写
我正在寻找 First() 聚合函数。
在这里,我发现了一些几乎有效的东西:
CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $1;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.first (
sfunc = public.first_agg,
basetype = anyelement,
stype = anyelement
);
Run Code Online (Sandbox Code Playgroud)
问题是当 varchar(n) 列通过 first() 函数时,它会被转换为简单的 varchar(没有大小)。尝试在函数中将查询返回为 RETURNS SETOF anyelement,我收到以下错误:
错误:查询的结构与函数结果类型 Estado de SQL:42804 不匹配:返回的类型字符变化与第 2 列中的预期类型字符变化(40) 不匹配。上下文:PL/pgSQL 函数 vsr_table_at_time(anyelement,timestamp without time zone ) 第 31 行在 RETURN QUERY
在同一个 wiki 页面中,有一个指向该函数 …
我运行了一个 SQL Server 2016 数据库,其中有一个包含 100 多万行的下表:
StationId | ParameterId | DateTime | Value
1 | 2 | 2020-02-04 15:00:000 | 5.20
1 | 2 | 2020-02-04 14:00:000 | 5.20
1 | 2 | 2020-02-04 13:00:000 | 5.20
1 | 3 | 2020-02-04 15:00:000 | 2.81
1 | 3 | 2020-02-04 14:00:000 | 2.81
1 | 4 | 2020-02-04 15:00:000 | 5.23
2 | 2 | 2020-02-04 15:00:000 | 3.70
2 | 4 | 2020-02-04 15:00:000 | 12.20
3 | …Run Code Online (Sandbox Code Playgroud) index sql-server optimization greatest-n-per-group sql-server-2016
这里有两张桌子。
学校员工
SCHOOL_CODE + STAFF_TYPE_NAME + LAST_UPDATE_DATE_TIME + PERSON_ID
=================================================================
ABE Principal 24-JAN-13 111222
ABE Principal 09-FEB-12 222111
Run Code Online (Sandbox Code Playgroud)
人
PERSON_ID + NAME
=================
111222 ABC
222111 XYZ
Run Code Online (Sandbox Code Playgroud)
这是我的 oracle 查询。
SELECT MAX(LAST_UPDATE_DATE_TIME) AS LAST_UPDATE, SCHOOL_CODE, PERSON_ID
FROM SCHOOL_STAFF
WHERE STAFF_TYPE_NAME='Principal'
GROUP BY SCHOOL_CODE, PERSON_ID
ORDER BY SCHOOL_CODE;
Run Code Online (Sandbox Code Playgroud)
这给出了这个结果
LAST_UPDATE SCHOOL_CODE PERSON_ID
===========+===========+=========
24-JAN-13 ABE 111222
09-FEB-12 ABE 222111
Run Code Online (Sandbox Code Playgroud)
我想为日期最晚的学校选择第一个。
谢谢。
鉴于表:
Column | Type
id | integer
latitude | numeric(9,6)
longitude | numeric(9,6)
speed | integer
equipment_id | integer
created_at | timestamp without time zone
Indexes:
"geoposition_records_pkey" PRIMARY KEY, btree (id)
Run Code Online (Sandbox Code Playgroud)
该表有 2000 万条记录,相对而言,这不是一个大数目。但它会使顺序扫描变慢。
我怎样才能获得max(created_at)每个的最后一条记录 ( ) equipment_id?
我已经尝试了以下两个查询,其中有几个变体,我已经阅读了本主题的许多答案:
select max(created_at),equipment_id from geoposition_records group by equipment_id;
select distinct on (equipment_id) equipment_id,created_at
from geoposition_records order by equipment_id, created_at desc;
Run Code Online (Sandbox Code Playgroud)
我也尝试过创建 btree 索引,equipment_id,created_at但 Postgres 发现使用 seqscan 更快。强制enable_seqscan = off也没有用,因为读取索引与 seq 扫描一样慢,可能更糟。
查询必须定期运行,始终返回最后一个。
使用 Postgres …
id value
1 50
2 60
3 55
select max(value) from tablename;
Run Code Online (Sandbox Code Playgroud)
一般我们知道,我们会得到 60,但我需要下一个值 55。
如何使用 SQL 获取值 55?
我station_logs在 PostgreSQL 9.6 数据库中有一个表:
Column | Type |
---------------+-----------------------------+
id | bigint | bigserial
station_id | integer | not null
submitted_at | timestamp without time zone |
level_sensor | double precision |
Indexes:
"station_logs_pkey" PRIMARY KEY, btree (id)
"uniq_sid_sat" UNIQUE CONSTRAINT, btree (station_id, submitted_at)
Run Code Online (Sandbox Code Playgroud)
我试图level_sensor根据submitted_at, 对于每个station_id. 大约有 400 个唯一station_id值,每个station_id.
创建索引之前:
EXPLAIN ANALYZE
SELECT DISTINCT ON(station_id) station_id, submitted_at, level_sensor
FROM station_logs ORDER BY station_id, submitted_at DESC;
Run Code Online (Sandbox Code Playgroud)
唯一(成本=4347852.14..4450301.72行=89宽度=20)(实际时间=22202.080..27619.167行=98循环=1) -> Sort …
postgresql performance greatest-n-per-group postgresql-9.6 query-performance
这与这个问题有关: Joining multiple tables results in duplicate rows
我有两个要加入的表。他们共用一个钥匙。person 表的每个主键有一个名称,而 email 表的每个 personId 有多个电子邮件。我只想显示每个人的第一封电子邮件。目前我每人收到多行,因为他们有多封电子邮件。我正在运行 SQL-Server 2005。
编辑:这是 T-SQL。第一封电子邮件实际上是每个人的第一封电子邮件行。
编辑 2:我看到的第一封电子邮件将是在 SQL 通过查询工作时显示在联接中的第一封电子邮件行。我不管出现哪个电子邮件。只是显示不超过一封电子邮件。我希望这能让它更清楚。
Table1: Person
Table2: Email
Select Person.PersonName, Email.Email
From person
left join on Person.ID=Email.PersonId;
Run Code Online (Sandbox Code Playgroud) postgresql ×4
sql-server ×4
performance ×3
index ×2
oracle ×2
aggregate ×1
functions ×1
optimization ×1
t-sql ×1