选择具有多列主键的行。

huangapple go评论76阅读模式
英文:

SELECT rows with primary key of multiple columns

问题

如何根据提供的一对列表选择所有相关记录?

表格:

CREATE TABLE "users_groups" (
    "user_id" INTEGER NOT NULL,
    "group_id" BIGINT NOT NULL,
    PRIMARY KEY (user_id, group_id),
    "permissions" VARCHAR(255)
);

例如,如果我有以下JavaScript array,我应该从数据库中获取这些数据:

[
  {user_id: 1, group_id: 19},
  {user_id: 1, group_id: 11},
  {user_id: 5, group_id: 19}
]

在这里,我们可以看到相同的 user_id 可能属于多个组。

我可以使用 for-loop 遍历每个数组元素并创建以下 查询

SELECT * FROM users_groups
    WHERE (user_id = 1 AND group_id = 19) 
    OR (user_id = 1 AND group_id = 11) 
    OR (user_id = 5 AND group_id = 19);

但这是否是最佳解决方案?假设数组非常长。据我所知,查询长度可能会达到约 1GB

有什么最佳和快速的解决方案吗?

英文:

How do I select all relevant records according to the provided list of pairs?

table:

CREATE TABLE "users_groups" (
    "user_id" INTEGER NOT NULL,
    "group_id" BIGINT NOT NULL,
    PRIMARY KEY (user_id, group_id),
    "permissions" VARCHAR(255)
);

For example, if I have the following JavaScript array of pairs that I should get from DB

[
  {user_id: 1, group_id: 19},
  {user_id: 1, group_id: 11},
  {user_id: 5, group_id: 19}
]

Here we see that the same user_id can be in multiple groups.

I can pass with for-loop over every array element and create the following query:

SELECT * FROM users_groups
    WHERE (user_id = 1 AND group_id = 19) 
    OR (user_id = 1 AND group_id = 11) 
    OR (user_id = 5 AND group_id = 19);

But is this the best solution? Let say if the array is very long. As I know query length may get ~1GB.

what is the best and quick solution to do this?

答案1

得分: 2

Bill Karwin的回答在Postgres中同样有效。

然而,我有这样的经验,与VALUES子句连接往往比大型IN列表(具有数百甚至数千个元素)更快:

select ug.*
from user_groups ug
  join ( 
     values (1,19), (1,11), (5,19), ... 
  ) as l(uid, guid) on l.uid = ug.user_id and l.guid = ug.group_id;

这假设提供的值中没有重复项,否则JOIN将导致重复的行,而IN解决方案不会这样做。

英文:

Bill Karwin's answer will work for Postgres just as well.

However, I have made the experience that joining against a VALUES clause is very often faster than a large IN list (with hundreds if not thousands of elements):

select ug.*
from user_groups ug
  join ( 
     values (1,19), (1,11), (5,19), ... 
  ) as l(uid, guid) on l.uid = ug.user_id and l.guid = ug.group_id;

This assumes that there are no duplicates in the values provided, otherwise the JOIN would result in duplicated rows, which the IN solution would not do.

答案2

得分: 1

你同时标记了mysql和postgresql,所以我不知道你实际使用哪个SQL数据库。

至少MySQL支持元组比较:

SELECT * FROM users_groups WHERE (user_id, group_id) IN ((1,19), (1,11), (5,19), ...)

这种谓词可以在MySQL 5.7及更高版本中进行优化。请参阅https://dev.mysql.com/doc/refman/5.7/en/range-optimization.html#row-constructor-range-optimization

我不知道PostgreSQL是否支持这种类型的谓词,或者是否对其进行了优化。

英文:

You tagged both mysql and postgresql, so I don't know which SQL database you're really using.

MySQL at least supports tuple comparisons:

SELECT * FROM users_groups WHERE (user_id, group_id) IN ((1,19), (1,11), (5,19), ...)

This kind of predicate can be optimized in MySQL 5.7 and later. See https://dev.mysql.com/doc/refman/5.7/en/range-optimization.html#row-constructor-range-optimization

I don't know whether PostgreSQL supports this type of predicate, or if it optimizes it.

huangapple
  • 本文由 发表于 2020年1月4日 01:06:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/59582539.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定