选择DISTINCT最多返回一行



给定以下数据库结构:

区域

id 名称
1 欧盟
2 美国
3 SEA

还有一个PL/pgSQL函数,定义为sendShipment((,它接受(除其他外(发送方和接收方客户ID。

这方面有一个业务约束,要求我们验证发送方和接收方是否位于同一区域,并且我们需要将此作为sendShipment((的一部分来执行。因此,在这个函数中,我们需要在客户表中查询发送方和接收方ID,并验证它们的区域ID是否相同。我们还需要对自己进行身份验证,以便后续进行进一步处理。

此查询应该有效:

WITH q AS (
SELECT
COUNT( * ) AS CountCustomers,
COUNT( DISTINCT c.Region ) AS CountDistinctRegions,
--      MIN( c.Region ) AS MinRegion
FIRST_VALUE( c.Region ) OVER ( ORDER BY c.Region ) AS MinRegion
FROM
Customers AS c
WHERE
c.CustomerId = $senderCustomerId
OR
c.CustomerId = $receiverCustomerId
)
SELECT
CASE WHEN q.CountCustomers = 2 AND q.CountDistinctRegions = 2 THEN 'OK' ELSE 'BAD' END AS "Status",
CASE WHEN q.CountDistinctRegions = 2 THEN q.MinRegion END AS SingleRegion
FROM
q
  • 上述查询将始终返回一行,其中包含两列:StatusSingleRegion

  • SQL没有一个;CCD_ 3";聚合函数(即,除非聚合组只有一行,否则为NULL的函数(,但我们可以在CTE或派生表中使用MIN(或MAX(和CASE WHEN COUNT()作为等效操作
    • 或者,可以使用窗口函数,但令人恼火的是,它们在GROUP BY查询中不起作用,尽管它们非常相似,argh
      • 再一次,这是ISO SQL委员会的错,而不是PostgreSQL的错
  • 由于您的Region列是UUID,您不能将其与MIN一起使用,但我理解它应该与FIRST_VALUE( c.Region ) OVER ( ORDER BY c.Region ) AS MinRegion一起使用。

  • 关于列:

    • Status列是'OK''BAD',这取决于您提到的那些业务约束。不过,您可能希望将其更改为bit列,而不是文本列
    • 如果CountDistinctRegions = 2而不考虑CountCustomers,则SingleRegion列将为NOT NULL(具有有效区域(,但请随意更改,以防您仍然需要该信息

对于其他对简单解决方案感兴趣的人,我终于想出了(有点明显(的方法:

SELECT
r.region
FROM
customers s
INNER JOIN customers r ON 
s.region = r.region 
WHERE s.id = 'sender_id' and r.id = 'receiver_id';

SELECT DISTINCT最多只返回了一行,他在这方面帮了我很多忙,还发布了一个可行的解决方案。

最新更新