【问题标题】:Pick one row for each pair of parent-child and child-parent relationships为每对父子关系和子父关系选择一行
【发布时间】:2016-07-18 23:53:10
【问题描述】:

我被这个问题困住了,我可以寻求帮助。

我正在使用一个名为 dependencies 的表。

一个简单的例子

ID, parent, dependent, relationship
1234, John, Mike, Parent
1235, Mike, John, Child
1236, Nancy, John, Spouse
1237, John, Nancy, Spouse
1238, Peter, Mike, Sibling
1239, Mike, Peter, Sibling

其中一些依赖是“镜像依赖”(如 1234 和 1235)

  • 约翰是迈克的父母
  • 迈克是约翰的孩子

要求是每对用户检索一个关系,意思是 我们需要为每一对 (John, Mike)(John, Nancy)(Peter, Mike) 包含一条记录(实际上person_key 代替名称,所以不应该有任何重复,但为了示例,我使用名称)

1234, John, Mike, Parent
1237, John, Nancy, Spouse
1238, Peter, Mike, Sibling

1235, Mike, John, Child
1236, Nancy, John, Spouse
1239, Mike, Peter, Sibling

知道如何使用 SQL 来跳过集合中的镜像记录吗?

【问题讨论】:

  • 像这样跳过结果集并不容易,您需要先拆分表(使用逗号作为分隔符的标准拆分函数),然后使用拆分搜索匹配项,然后只选择第一个匹配项或没有匹配项(如果可能的话)。

标签: sql sql-server


【解决方案1】:

样本数据

DECLARE @Dependencies TABLE
([ID] int, [parent] varchar(50), [dependent] varchar(50), [relationship] varchar(50));

INSERT INTO @Dependencies
([ID], [parent], [dependent], [relationship])
VALUES
(1234, 'John', 'Mike', 'Parent'),
(1235, 'Mike', 'John', 'Child'),
(1236, 'Nancy', 'John', 'Spouse'),
(1237, 'John', 'Nancy', 'Spouse'),
(1238, 'Peter', 'Mike', 'Sibling'),
(1239, 'Mike', 'Peter', 'Sibling');

查询

计算(parent, dependent) 中的MINMAX,然后您可以将它们组合在一起。

SELECT
    ID
    ,CASE WHEN [parent] < [dependent] THEN [parent] ELSE [dependent] END AS MinRelationship
    ,CASE WHEN [parent] > [dependent] THEN [parent] ELSE [dependent] END AS MaxRelationship
    ,[relationship]
FROM @Dependencies
;

结果

+------+-----------------+-----------------+--------------+
|  ID  | MinRelationship | MaxRelationship | relationship |
+------+-----------------+-----------------+--------------+
| 1234 | John            | Mike            | Parent       |
| 1235 | John            | Mike            | Child        |
| 1236 | John            | Nancy           | Spouse       |
| 1237 | John            | Nancy           | Spouse       |
| 1238 | Mike            | Peter           | Sibling      |
| 1239 | Mike            | Peter           | Sibling      |
+------+-----------------+-----------------+--------------+

其余的取决于您要从每对中选择哪一行。例如,我们可能希望选择ID 最小的行。 CTE_MinMax 是上面的简单查询。 CTE_rn 将一个数字添加到由该对分区并按 ID 排序的每一行。最后的SELECT 每对只返回一行。

如果只有一个条目(不是一对),或者有两个以上的条目,查询将正常工作。

WITH
CTE_MinMax
AS
(
    SELECT
        ID
        ,CASE WHEN [parent] < [dependent] THEN [parent] ELSE [dependent] END AS MinRelationship
        ,CASE WHEN [parent] > [dependent] THEN [parent] ELSE [dependent] END AS MaxRelationship
        ,[relationship]
    FROM @Dependencies
)
,CTE_rn
AS
(
    SELECT
        ID
        ,MinRelationship
        ,MaxRelationship
        ,relationship
        ,ROW_NUMBER() OVER (PARTITION BY MinRelationship, MaxRelationship ORDER BY ID) AS rn
    FROM CTE_MinMax
)
SELECT
    ID
    ,MinRelationship
    ,MaxRelationship
    ,relationship
FROM CTE_rn
WHERE rn = 1
;

结果

+------+-----------------+-----------------+--------------+
|  ID  | MinRelationship | MaxRelationship | relationship |
+------+-----------------+-----------------+--------------+
| 1234 | John            | Mike            | Parent       |
| 1236 | John            | Nancy           | Spouse       |
| 1238 | Mike            | Peter           | Sibling      |
+------+-----------------+-----------------+--------------+

【讨论】:

  • 谢谢你的想法!!通过案例计算最小值和最大值使我可以分组并准确检索我需要的内容我非常感谢您的回答
【解决方案2】:

我想我实际上会在表中只为关系存储一条记录。所以你不会添加 1239, Mike, Peter, Sibling 记录,因为你已经有 Mike 和 Peter 的记录。然后在父/子关系的情况下,您可以假设父级始终位于“父级”列中,而“子级”位于从属列中。

所以基本上你在表格中的所有内容都是:

1234, John, Mike, Parent
1237, John, Nancy, Spouse
1238, Peter, Mike, Sibling

因此,如果您正在寻找迈克的父母,您可以这样做:

select * from table where dependent = 'Mike' and relationship = 'Parent'

如果您正在寻找约翰的配偶:

select * from table where (parent = 'John' or dependent = 'John') and relationship = 'Spouse'

如果您正在寻找彼得的兄弟姐妹:

select * from table where (parent = 'Peter' or dependent = 'Peter') and relationship = 'Sibling'

无论如何我都是这样处理它的,这将使您的查询比尝试跳过“镜像记录”简单得多。

【讨论】:

  • 嗨,Jacob,感谢您的帮助我很想以其他方式存储数据,但我们以该格式接收数据。我的目标是每对只检索一条记录,该表包含数千条记录,因此不像每对创建一个查询那么简单。如果我需要检索一条记录,您的解决方案会很好用,但我的情况比表中的一条记录更普遍。再次感谢
猜你喜欢
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 2018-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多