如何查询缺少的字段和关联以及 return PostgreSQL 中缺少什么?
How to query for missing fields and associations and return what's missing in PostgreSQL?
在学习了多年 Rails 和其他 ORM 之后,我正在学习更多原始知识 SQL,因此有很多方法可以学习如何有效地进行复杂查询。我想知道的是_如何找到所有缺少某些字段和关联的用户,以及 return他们缺少哪些 fields/associations。
我对如何在 SQL 中写这个有一个粗略的想法,但不准确(对于 PostgreSQL)。
我有类似这个数据模型的东西,一个 table 用户,一个 table 个“社交媒体 link”,以及一个映射 link 的关联给用户,因此一个用户可以拥有多个社交媒体 link,但可能有多个用户与一个 link(即组织)相关联:
CREATE TABLE users (
id INT GENERATED BY DEFAULT AS IDENTITY,
slug VARCHAR(255) NOT NULL,
name VARCHAR(255),
description TEXT,
PRIMARY KEY (id)
)
CREATE TABLE sociallinks (
id INT GENERATED BY DEFAULT AS IDENTITY,
type VARCHAR(255),
value TEXT,
PRIMARY KEY (id)
)
CREATE TABLE usersociallinks (
id INT GENERATED BY DEFAULT AS IDENTITY,
user_id INTEGER REFERENCES users;
sociallink_id INTEGER REFERENCES sociallinks,
PRIMARY KEY (id)
)
问题是,您如何执行查询(使用此伪代码):
select from users
join on usersociallinks.user_id = users.id
join on sociallinks.id = usersociallinks.id
where name = null
or description = null
or missing linkedin? (sociallinks.type == linkedin)
or missing facebook? (sociallinks.type == facebook)
return slug from users table
return has_name = false if name is null from users table
return has_description = false if description is null from users table
return has_linkedin = false if linkedin is null from sociallinks table
return has_facebook = false if facebook is null from sociallinks table
在自然语言中,“select 没有姓名或描述,或者缺少 linkedin 或 facebook link 的用户(sociallinks.value),以及 return 他们缺少哪些字段。
我可以用天真、冗长和复杂的方式或一次查询一件事来做到这一点,但我想知道如何有效地做到这一点,可能只用一个查询(或尽可能少的查询)。
SELECT * FROM users
WHERE name IS NULL
OR description IS NULL
LIMIT 1
获取那些,然后执行:
const record = await knex.raw(SQL)
const output = {}
if (!record.name) output.hasName = false
if (!record.description) output.hasDescription = false
return output
然后下一个查询会更复杂,但我会一次做一个。
您如何在尽可能少的查询中高效地做到这一点?每次查询限制为 100 个用户。
输入数据为:
users:
id,slug,name,description
1,foo,Foo,Im a description
2,bar,,Im a description too
3,baz,,
4,hello,Hello,
5,world,,
6,food,Foo,Im a descriptiond
7,bard,,Im a description tood
8,bazd,asdf,fdsa
9,hellod,,
10,worldd,,A worldd description
sociallinks:
id,type,value
1,facebook,foo
2,facebook,bar
3,facebook,baz
4,facebook,hello
5,facebook,world
6,linkedin,foo
7,linkedin,bar
8,linkedin,baz
9,linkedin,hello
10,linkedin,world
usersociallinks:
id,user_id,sociallink_id
1,1,1
2,2,2
3,2,6
4,3,7
5,5,3
6,8,4
7,8,8
8,9,9
输出数据为:
user_id,slug,has_name,has_description,has_linkedin,has_facebook
1,foo,true,true,false,true
2,bar,false,true,true,true
3,baz,false,false,true,false
4,hello,true,false,false,false
5,world,false,false,false,true
6,food,true,true,false,false
7,bard,false,true,false,false
// 8 has everything so it is missing
9,hellod,false,false,true,false
10,worldd,false,true,false,false
select the users which either don't have a name or a description, or are missing a linkedin or facebook link (sociallinks.value), and return what fields they are missing
我想两个 left join
s:
with usl as (
select usl.*, sl.type
from usersociallinks usl join
sociallinks sl
on sl.id = usl.sociallink_id
)
select concat_ws(',',
(case when u.name is null then 'name' end),
(case when u.description is null then 'description' end),
(case when usl_f.user_id is null then 'facebook' end),
(case when usl_l.user_id is null then 'linkedin' end)
) as missing_values
from users u left join
usl usl_f
on usl_f.user_id = u.id and usl_f.value = 'facebook' left join
usl usl_l
on usl_l.user_id = u.id and usl_l.value = 'linkedin'
where u.name is null or u.description is null or
usl_f.user_id is null or usl_l.user_id is null
您可以连接表并使用条件聚合:
SELECT u.id, u.slug,
MAX(name) IS NOT NULL has_name,
MAX(description) IS NOT NULL has_description,
MAX(CASE WHEN s.type = 'linkedin' THEN 1 ELSE 0 END)::boolean has_linkedin,
MAX(CASE WHEN s.type = 'facebook' THEN 1 ELSE 0 END)::boolean has_facebook
FROM users u
LEFT JOIN usersociallinks usl ON usl.user_id = u.id
LEFT JOIN sociallinks s ON s.id = usl.sociallink_id AND s.type IN ('facebook', 'linkedin')
GROUP BY u.id, u.slug
ORDER BY u.id
参见demo。
EXISTS()
救援:
SELECT u.id, u.slug
, (u.name > '' ) AS has_name
, (u.description> '' ) AS has_description
, EXISTS(SELECT 1 FROM usersociallinks sl JOIN sociallinks s ON s.id = usl.sociallink_i
WHERE sl.user_id = u.id AND s.type = 'facebook') AS has_facebook
, EXISTS(SELECT 1 FROM usersociallinks sl JOIN sociallinks s ON s.id = usl.sociallink_i
WHERE sl.user_id = u.id AND s.type = 'linkedin') AS has_linkedin
FROM users u
ORDER BY u.id
;
在学习了多年 Rails 和其他 ORM 之后,我正在学习更多原始知识 SQL,因此有很多方法可以学习如何有效地进行复杂查询。我想知道的是_如何找到所有缺少某些字段和关联的用户,以及 return他们缺少哪些 fields/associations。
我对如何在 SQL 中写这个有一个粗略的想法,但不准确(对于 PostgreSQL)。
我有类似这个数据模型的东西,一个 table 用户,一个 table 个“社交媒体 link”,以及一个映射 link 的关联给用户,因此一个用户可以拥有多个社交媒体 link,但可能有多个用户与一个 link(即组织)相关联:
CREATE TABLE users (
id INT GENERATED BY DEFAULT AS IDENTITY,
slug VARCHAR(255) NOT NULL,
name VARCHAR(255),
description TEXT,
PRIMARY KEY (id)
)
CREATE TABLE sociallinks (
id INT GENERATED BY DEFAULT AS IDENTITY,
type VARCHAR(255),
value TEXT,
PRIMARY KEY (id)
)
CREATE TABLE usersociallinks (
id INT GENERATED BY DEFAULT AS IDENTITY,
user_id INTEGER REFERENCES users;
sociallink_id INTEGER REFERENCES sociallinks,
PRIMARY KEY (id)
)
问题是,您如何执行查询(使用此伪代码):
select from users
join on usersociallinks.user_id = users.id
join on sociallinks.id = usersociallinks.id
where name = null
or description = null
or missing linkedin? (sociallinks.type == linkedin)
or missing facebook? (sociallinks.type == facebook)
return slug from users table
return has_name = false if name is null from users table
return has_description = false if description is null from users table
return has_linkedin = false if linkedin is null from sociallinks table
return has_facebook = false if facebook is null from sociallinks table
在自然语言中,“select 没有姓名或描述,或者缺少 linkedin 或 facebook link 的用户(sociallinks.value),以及 return 他们缺少哪些字段。
我可以用天真、冗长和复杂的方式或一次查询一件事来做到这一点,但我想知道如何有效地做到这一点,可能只用一个查询(或尽可能少的查询)。
SELECT * FROM users
WHERE name IS NULL
OR description IS NULL
LIMIT 1
获取那些,然后执行:
const record = await knex.raw(SQL)
const output = {}
if (!record.name) output.hasName = false
if (!record.description) output.hasDescription = false
return output
然后下一个查询会更复杂,但我会一次做一个。
您如何在尽可能少的查询中高效地做到这一点?每次查询限制为 100 个用户。
输入数据为:
users:
id,slug,name,description
1,foo,Foo,Im a description
2,bar,,Im a description too
3,baz,,
4,hello,Hello,
5,world,,
6,food,Foo,Im a descriptiond
7,bard,,Im a description tood
8,bazd,asdf,fdsa
9,hellod,,
10,worldd,,A worldd description
sociallinks:
id,type,value
1,facebook,foo
2,facebook,bar
3,facebook,baz
4,facebook,hello
5,facebook,world
6,linkedin,foo
7,linkedin,bar
8,linkedin,baz
9,linkedin,hello
10,linkedin,world
usersociallinks:
id,user_id,sociallink_id
1,1,1
2,2,2
3,2,6
4,3,7
5,5,3
6,8,4
7,8,8
8,9,9
输出数据为:
user_id,slug,has_name,has_description,has_linkedin,has_facebook
1,foo,true,true,false,true
2,bar,false,true,true,true
3,baz,false,false,true,false
4,hello,true,false,false,false
5,world,false,false,false,true
6,food,true,true,false,false
7,bard,false,true,false,false
// 8 has everything so it is missing
9,hellod,false,false,true,false
10,worldd,false,true,false,false
select the users which either don't have a name or a description, or are missing a linkedin or facebook link (sociallinks.value), and return what fields they are missing
我想两个 left join
s:
with usl as (
select usl.*, sl.type
from usersociallinks usl join
sociallinks sl
on sl.id = usl.sociallink_id
)
select concat_ws(',',
(case when u.name is null then 'name' end),
(case when u.description is null then 'description' end),
(case when usl_f.user_id is null then 'facebook' end),
(case when usl_l.user_id is null then 'linkedin' end)
) as missing_values
from users u left join
usl usl_f
on usl_f.user_id = u.id and usl_f.value = 'facebook' left join
usl usl_l
on usl_l.user_id = u.id and usl_l.value = 'linkedin'
where u.name is null or u.description is null or
usl_f.user_id is null or usl_l.user_id is null
您可以连接表并使用条件聚合:
SELECT u.id, u.slug,
MAX(name) IS NOT NULL has_name,
MAX(description) IS NOT NULL has_description,
MAX(CASE WHEN s.type = 'linkedin' THEN 1 ELSE 0 END)::boolean has_linkedin,
MAX(CASE WHEN s.type = 'facebook' THEN 1 ELSE 0 END)::boolean has_facebook
FROM users u
LEFT JOIN usersociallinks usl ON usl.user_id = u.id
LEFT JOIN sociallinks s ON s.id = usl.sociallink_id AND s.type IN ('facebook', 'linkedin')
GROUP BY u.id, u.slug
ORDER BY u.id
参见demo。
EXISTS()
救援:
SELECT u.id, u.slug
, (u.name > '' ) AS has_name
, (u.description> '' ) AS has_description
, EXISTS(SELECT 1 FROM usersociallinks sl JOIN sociallinks s ON s.id = usl.sociallink_i
WHERE sl.user_id = u.id AND s.type = 'facebook') AS has_facebook
, EXISTS(SELECT 1 FROM usersociallinks sl JOIN sociallinks s ON s.id = usl.sociallink_i
WHERE sl.user_id = u.id AND s.type = 'linkedin') AS has_linkedin
FROM users u
ORDER BY u.id
;