PostgreSQL:用于确定不同行的自定义逻辑?

PostgreSQL:用于确定不同行的自定义逻辑?,postgresql,distinct,Postgresql,Distinct,这是我的问题。假设我有一个名为persons的表,其中包含个人姓名和国家识别号字段,后者是可选的。每个实际人员可以有多行 现在假设我想为每个实际的人选择一行。在应用程序中,如果a)他们的ID号匹配,或b)他们的姓名匹配,且其中一行或两行的ID号均为空,则认为两行表示同一个人。在这里选择DISTINCT不好:我不能在(name,id)上执行DISTINCT,因为如果其中一行的id为NULL,那么具有相同名称的两行将不匹配(这是不正确的,它们应该被认为是相同的)。我无法在(名称)上执行区分,因为这样

这是我的问题。假设我有一个名为
persons
的表,其中包含个人姓名和国家识别号字段,后者是可选的。每个实际人员可以有多行

现在假设我想为每个实际的人选择一行。在应用程序中,如果a)他们的ID号匹配,或b)他们的姓名匹配,且其中一行或两行的ID号均为空,则认为两行表示同一个人。在这里选择DISTINCT不好:我不能在(name,id)上执行
DISTINCT,因为如果其中一行的id为NULL,那么具有相同名称的两行将不匹配(这是不正确的,它们应该被认为是相同的)。我无法在(名称)
上执行
区分,因为这样,具有相同名称但不同ID的行将匹配(同样不正确,它们应被视为不同)。我不能在(id)
上进行
区分,因为这样id为NULL的所有行都会被认为是相同的(显然是不正确的)

有没有办法重新定义PostgreSQL比较行的方式,以确定它们是否相同?我猜
DISTINCT ON(name,id)
的默认行为类似于
如果a.name=b.name和a.id=b.id,那么相同的其他DISTINCT
。我想将其重新定义为
如果a.id=b.id或(a.name=b.name和(a.id为NULL或b.id为NULL)),则相同或不同


现在已经很晚了,我可能错过了一些明显的东西,所以关于如何实现我想要的东西的其他建议也很受欢迎。使我能够基于比简单列列表更复杂的条件选择不同行的任何内容。提前感谢。

看来主要问题是数据库的布局。我不知道您的特定应用程序的详细信息,但是为同一个人设置多行和空ID通常是个坏主意。如果可能的话,您可以考虑为需要多行的任何信息创建一个单独的表,其中<>代码>人>代码>只包含每个人的一行和每行的唯一标识符。 但是,如果你不能做到这一点。。。我不认为一个独特的解决方案就能解决这个问题

有什么问题吗

select distinct name, id
from persons
where id is not null
你是否有一些人有名字,但没有身份证?或者您需要其他行中的特定数据吗


还有一个问题:如果有两行具有相同的名称和空ID,并且有多个人具有相同的名称和不同的ID,那么如何知道空行与哪个人匹配?

使用窗口函数 没有窗口功能 通过每个非空id的第一个(
MIN()
)名称将上述
联合
替换为一个
组:

...
UNION ALL
  SELECT MIN(name) AS name, id
    FROM persons
   WHERE id IS NOT NULL
GROUP BY id

是的,数据库结构不是最优的,我实际上正在改变它。如您所述,
persons
表将每个人包含一行,但要做到这一点,我需要一种方法将所有现有行压缩为一行。这就是问题所在。是的,我有一些人有名字但没有ID。就像我上面说的,ID字段是可选的。否则,我只需
在(id)上选择DISTINCT即可
“这是另一个问题:如果有两行具有相同的名称和空id,并且有多个人具有相同的名称和不同的id,您如何知道空行匹配的人?”不存在这样的行,因此这是一个没有实际意义的问题。感谢您的建议。但是,我使用的是PostgreSQL 8.1,它没有窗口函数。。。union all从id不为的人员中选择不同的名称、idnull@Corey,对于以下表示同一个人的
(姓名、id)
元组对,这将失败:
('Bob Jones',123)
('Robert A.Jones',123)
@Indrek,我已更新了我的答案以适应8.1。你应该更新你的postgresql:)@pilcrow恐怕不是我能决定的。我得将就一下。谢谢你更新的答案,它让我走上了正确的道路。这并不是我所需要的,因为我还必须选择其他字段(我的缺点是在原始帖子中没有提到这一点),在第二个查询中按这些字段分组会导致两行不同的电话号码被视为不同的人。A
。。。UNION ALL SELECT DISTINCT ON(id)*FROM persons…
修复了这一问题。我已将你的答复标记为已接受的答复。再次感谢你的帮助!
...
UNION ALL
  SELECT MIN(name) AS name, id
    FROM persons
   WHERE id IS NOT NULL
GROUP BY id