SELECT DISTINCT 最多返回一行
给定以下数据库结构:
Regions
id | name |
---|---|
1 | EU |
2 | US |
3 | SEA |
Customers:
id | name | region |
---|---|---|
1 | peter | 1 |
2 | henry | 1 |
3 | john | 2 |
还有一个 PL/pgSQL函数到位,定义为 sendShipment()
,它接受(除其他外)发送者和接收者客户 ID。
这存在一个业务限制,要求我们验证发送方和接收方是否位于同一区域 - 并且我们需要将其作为 sendShipment()
的一部分来执行。因此,在此函数中,我们需要查询客户表中的发送者和接收者 ID,并验证它们的区域 ID 是否相同。我们还需要识别自身以便进一步处理。
所以也许是这样的: SELECT DISTINCT Region FROM Customers WHERE id IN (?, ?)
这样做的问题是,结果要么是一个数组(如果客户不在同一区域内),要么是单个值。
有没有更优雅的方法来解决这个约束?我正在考虑SELECT INTO
并使用临时表,或者我可以SELECT COUNT(DISTINCTregion)
然后为实际的数据执行另一个SELECT
如果计数小于 2,则为值,但我希望尽可能避免性能受到影响。
Given the following db structure:
Regions
id | name |
---|---|
1 | EU |
2 | US |
3 | SEA |
Customers:
id | name | region |
---|---|---|
1 | peter | 1 |
2 | henry | 1 |
3 | john | 2 |
There is also a PL/pgSQL function in place, defined as sendShipment()
which takes (among other things) a sender and a receiver customer ID.
There is a business constraint around this which requires us to verify that both sender and receiver sit in the same region - and we need to do this as part of sendShipment()
. So from within this function, we need to query the customer table for both the sender and receiver ID and verify that both their region ID is identical. We will also need to ID itself for further processing down the line.
So maybe something like this:SELECT DISTINCT region FROM customers WHERE id IN (?, ?)
The problem with this is that the result will be either an array (if the customers are not within the same region) or a single value.
Is there are more elegant way of solving this constraint? I was thinking of SELECT INTO
and use a temporary table, or I could SELECT COUNT(DISTINCT region)
and then do another SELECT
for the actual value if the count is less than 2, but I'd like to avoid the performance hit if possible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
此查询应该有效:
上述查询将始终返回包含 2 列的单行:
Status
和SingleRegion
。SQL 没有“SINGLE( col )
”聚合函数(即函数为NULL
,除非聚合组只有一行) ,但我们可以在 CTE 或派生表中将MIN
(或MAX
)与CASE WHEN COUNT()
滥用作为等效操作< /del>.或者,可以使用窗口函数,但令人烦恼的是它们不适用于。GROUP BY
查询尽管非常相似,呃由于您的
Region
列是 UUID,因此您不能将其与MIN
一起使用,但我知道它应该与FIRST_VALUE( c.Region ) OVER ( ORDER BY c.Region ) AS MinRegion
.对于列:
Status
列可以是'OK'
或'BAD'
。不过,您可能希望将其更改为位
列,而不是文本列。CountDistinctRegions = 2
,无论CountCustomers
为何,SingleRegion
列将为NOT NULL
(具有有效区域) >,但请随意更改,以防万一您仍然需要该信息。This query should work:
The above query will always return a single row with 2 columns:
Status
andSingleRegion
.SQL doesn't have a ".SINGLE( col )
" aggregate function (i.e. a function that isNULL
unless the aggregation group has a single row), but we can abuseMIN
(orMAX
) with aCASE WHEN COUNT()
in a CTE or derived-table as an equivalent operationAlternatively, windowing-functions could be used, but annoyingly they don't work in.GROUP BY
queries despite being so similar, arghAs your
Region
column is UUID you cannot use it withMIN
, but I understand it should work withFIRST_VALUE( c.Region ) OVER ( ORDER BY c.Region ) AS MinRegion
.As for the columns:
Status
column is either'OK'
or'BAD'
based on those business-constraints you mentioned. You might want to change it to abit
column instead of a textual one, though.SingleRegion
column will beNOT NULL
(with a valid region) ifCountDistinctRegions = 2
regardless ofCountCustomers
, but feel free to change that, just-in-case you still want that info.对于对简单解决方案感兴趣的其他人,我最终想出了一种(明显的)方法:
SELECT DISTINCT 最多返回一行 他在这方面帮了我很多忙,而且发布了可行的解决方案。
For anybody else who's interested in a simple solution, I finally came up with the (kind of obvious) way to do it:
Huge credit to SELECT DISTINCT to return at most one row who helped me out a lot on this and also posted a viable solution.