PostgreSQL 在 json 属性 上加入 table 并首先从结果中获取最旧的结果,首先是空值
PostgreSQL join table on json property and get oldest first from result with nulls first
我得到了 2 table;域和事件。我正在尝试创建一个查询,该查询 returns 一个不同域的列表,该列表按最旧的事件(对于该域)排序,首先是空值,然后是不同的域。
基本上这个查询就可以完成工作:
SELECT * FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null ORDER BY domain, moment asc nulls first;
但是 'domain' 上的输出并不明显。
使用 'distinct on' 时,它会给出错误的输出,其中时间戳(时刻)不是事件中该域的最新时间戳 table:
SELECT distinct on (domain) domain,moment FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null ORDER BY domain, moment asc nulls first;
这似乎也行不通:
SELECT * FROM (SELECT DISTINCT on (domain) domain,moment,parent FROM "domains" left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1') AS domains ORDER BY moment asc nulls first;
下面的代码模拟了数据库和我需要不同的查询,而没有不同的修改行的顺序:
(哦,正如您将看到的,父级必须为空,因此它只选择顶级域。但这是一个简单的 'where'。)
create table domains (domain text, parent text);
insert into domains (domain, parent) values ('whosebug.com', null);
insert into domains (domain, parent) values ('test.whosebug.com', 'whosebug.com');
insert into domains (domain, parent) values ('github.com', null);
insert into domains (domain, parent) values ('example.com', null);
insert into domains (domain, parent) values ('google.com', null);
create table events (name text, attributes jsonb, moment timestamp with time zone);
insert into events (name, attributes, moment) values('event1', '{"domain": "example.com"}', '2011-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "github.com"}', '2012-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "whosebug.com"}', '2013-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "example.com"}', '2014-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "whosebug.com"}', '2015-01-01');
SELECT * FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null ORDER BY domain, moment asc nulls first;
如何让它工作?
您是否考虑过使用 row_number
window 函数?像
SELECT *
FROM
(
SELECT *, row_number() OVER (PARTITION BY events.attributes->>'domain' ORDER BY moment ASC) rn FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null
) a
WHERE rn = 1
ORDER BY domain, moment asc nulls first
内部查询使用 row_number() OVER (PARTITION BY events.attributes->>'domain' ORDER BY moment ASC) rn
创建一个字段,对于每个 events.attributes->>'domain'
分组,按 events.moment
的顺序编号。外部查询仅限制为每个分组的第一个并进行最终排序。
with nulls first
这是模棱两可的,因为您查询中的 moment
有两个不同的 NULL
来源,而 events.moment
可以是 NULL
- 我们不知道没有 table 定义:
LEFT JOIN
找不到右侧符合条件的行。
LEFT JOIN
在右侧找到符合条件的行,但是 moment IS NULL
.
假设 events.moment
被定义为 NOT NULL
,domains.domain
是 UNIQUE
,并且您想要列出没有符合条件的事件的域首先,其余的按最旧的事件优先。
Select 子查询中每个合格域的最旧事件。在开始的连接 before 聚合速度更快。参见:
- Query with LEFT JOIN not returning rows for count of 0
SELECT d.domain, e.moment
FROM domains d
LEFT JOIN (
SELECT DISTINCT ON (1)
attributes ->> 'domain' AS domain, moment
FROM events
WHERE name = 'event1'
ORDER BY 1, moment
) e USING (domain)
WHERE d.parent IS NULL
ORDER BY e.moment NULLS FIRST, d.domain;
我在 ORDER BY
中添加了 domain
,以按字母顺序对领带进行排序。
或者,虽然我们不需要 events
中的任何其他内容,但只需要:
SELECT d.domain, e.moment
FROM domains d
LEFT JOIN (
SELECT attributes ->> 'domain' AS domain, min(moment) AS moment
FROM events
WHERE name = 'event1'
GROUP BY 1
) e USING (domain)
WHERE d.parent IS NULL
ORDER BY e.moment NULLS FIRST, d.domain;
db<>fiddle here
参见:
- Select first row in each GROUP BY group?
如果事件中有许多域具有 name = 'event1'
,而这些域对该查询没有贡献,那么 LATERAL
子查询会更快。参见:
根据未公开的数据分布和基数,可能会有(多)更快的解决方案。 row_number()
从来没有 最快。 I have tried many times.
我得到了 2 table;域和事件。我正在尝试创建一个查询,该查询 returns 一个不同域的列表,该列表按最旧的事件(对于该域)排序,首先是空值,然后是不同的域。
基本上这个查询就可以完成工作:
SELECT * FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null ORDER BY domain, moment asc nulls first;
但是 'domain' 上的输出并不明显。 使用 'distinct on' 时,它会给出错误的输出,其中时间戳(时刻)不是事件中该域的最新时间戳 table:
SELECT distinct on (domain) domain,moment FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null ORDER BY domain, moment asc nulls first;
这似乎也行不通:
SELECT * FROM (SELECT DISTINCT on (domain) domain,moment,parent FROM "domains" left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1') AS domains ORDER BY moment asc nulls first;
下面的代码模拟了数据库和我需要不同的查询,而没有不同的修改行的顺序:
(哦,正如您将看到的,父级必须为空,因此它只选择顶级域。但这是一个简单的 'where'。)
create table domains (domain text, parent text);
insert into domains (domain, parent) values ('whosebug.com', null);
insert into domains (domain, parent) values ('test.whosebug.com', 'whosebug.com');
insert into domains (domain, parent) values ('github.com', null);
insert into domains (domain, parent) values ('example.com', null);
insert into domains (domain, parent) values ('google.com', null);
create table events (name text, attributes jsonb, moment timestamp with time zone);
insert into events (name, attributes, moment) values('event1', '{"domain": "example.com"}', '2011-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "github.com"}', '2012-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "whosebug.com"}', '2013-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "example.com"}', '2014-01-01');
insert into events (name, attributes, moment) values('event1', '{"domain": "whosebug.com"}', '2015-01-01');
SELECT * FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null ORDER BY domain, moment asc nulls first;
如何让它工作?
您是否考虑过使用 row_number
window 函数?像
SELECT *
FROM
(
SELECT *, row_number() OVER (PARTITION BY events.attributes->>'domain' ORDER BY moment ASC) rn FROM domains left join events on events.attributes ->> 'domain' = domains.domain AND events.name = 'event1' WHERE parent is null
) a
WHERE rn = 1
ORDER BY domain, moment asc nulls first
内部查询使用 row_number() OVER (PARTITION BY events.attributes->>'domain' ORDER BY moment ASC) rn
创建一个字段,对于每个 events.attributes->>'domain'
分组,按 events.moment
的顺序编号。外部查询仅限制为每个分组的第一个并进行最终排序。
with nulls first
这是模棱两可的,因为您查询中的 moment
有两个不同的 NULL
来源,而 events.moment
可以是 NULL
- 我们不知道没有 table 定义:
LEFT JOIN
找不到右侧符合条件的行。LEFT JOIN
在右侧找到符合条件的行,但是moment IS NULL
.
假设 events.moment
被定义为 NOT NULL
,domains.domain
是 UNIQUE
,并且您想要列出没有符合条件的事件的域首先,其余的按最旧的事件优先。
Select 子查询中每个合格域的最旧事件。在开始的连接 before 聚合速度更快。参见:
- Query with LEFT JOIN not returning rows for count of 0
SELECT d.domain, e.moment
FROM domains d
LEFT JOIN (
SELECT DISTINCT ON (1)
attributes ->> 'domain' AS domain, moment
FROM events
WHERE name = 'event1'
ORDER BY 1, moment
) e USING (domain)
WHERE d.parent IS NULL
ORDER BY e.moment NULLS FIRST, d.domain;
我在 ORDER BY
中添加了 domain
,以按字母顺序对领带进行排序。
或者,虽然我们不需要 events
中的任何其他内容,但只需要:
SELECT d.domain, e.moment
FROM domains d
LEFT JOIN (
SELECT attributes ->> 'domain' AS domain, min(moment) AS moment
FROM events
WHERE name = 'event1'
GROUP BY 1
) e USING (domain)
WHERE d.parent IS NULL
ORDER BY e.moment NULLS FIRST, d.domain;
db<>fiddle here
参见:
- Select first row in each GROUP BY group?
如果事件中有许多域具有 name = 'event1'
,而这些域对该查询没有贡献,那么 LATERAL
子查询会更快。参见:
根据未公开的数据分布和基数,可能会有(多)更快的解决方案。 row_number()
从来没有 最快。 I have tried many times.