Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL中为具有多个关系的相关地址创建新标识符?_Sql_Database_Azure_Join_Relational Database - Fatal编程技术网

如何在SQL中为具有多个关系的相关地址创建新标识符?

如何在SQL中为具有多个关系的相关地址创建新标识符?,sql,database,azure,join,relational-database,Sql,Database,Azure,Join,Relational Database,我有一个如下所示的数据集,包括地址和客户id。在本例中,多个客户可以发送到同一地址,一个客户可以发送到多个地址。我想使用它们之间的关系来创建一个新ID,该ID将所有相关地址和客户ID与一个新标识符连接起来 原始表格 期望输出表 挑战在于相关关联的数量可能是无限的,我下面的SQL只能跨两个连接工作 下面是我的SQL,它适用于这个小数据集,但当扩展到更多关系时,它将需要更多的联接。如果您有任何关于构建此结构的正确方法的想法,我们将不胜感激 CREATE TABLE #temp (address ch

我有一个如下所示的数据集,包括地址和客户id。在本例中,多个客户可以发送到同一地址,一个客户可以发送到多个地址。我想使用它们之间的关系来创建一个新ID,该ID将所有相关地址和客户ID与一个新标识符连接起来

原始表格

期望输出表

挑战在于相关关联的数量可能是无限的,我下面的SQL只能跨两个连接工作

下面是我的SQL,它适用于这个小数据集,但当扩展到更多关系时,它将需要更多的联接。如果您有任何关于构建此结构的正确方法的想法,我们将不胜感激

CREATE TABLE #temp (address char(40), id char(40))
INSERT INTO #temp VALUES ('11 rd', 'aa');
INSERT INTO #temp VALUES ('11 rd', 'ab');
INSERT INTO #temp VALUES ('21 dr', 'ac');
INSERT INTO #temp VALUES ('21 dr', 'ab');
INSERT INTO #temp VALUES ('31 rd', 'ad');
INSERT INTO #temp VALUES ('21 dr', 'abb');
INSERT INTO #temp VALUES ('41 dr', 'abb');

SELECT 
*
,DENSE_RANK() OVER(PARTITION BY id ORDER BY address ASC)as address_rank
,DENSE_RANK() OVER(PARTITION BY address ORDER BY id ASC)as id_rank
INTO #temp2 
FROM #temp 

SELECT a.address,a.id_rank,a.id,b.address as combined_address
INTO #temp3
FROM #temp2 a
LEFT JOIN #temp2 b ON a.id=b.id AND b.address_rank = 1

SELECT 
 a.address
,a.id
,DENSE_RANK() OVER(ORDER BY b.combined_address ASC)as new_id
FROM #temp3 a
LEFT JOIN #temp3 b ON a.combined_address=b.address and b.id_rank = 1

这是一个图形漫游问题。首先,我将重新表述一下数据。这有助于每一行都有一个唯一的标识符,该标识符被恰当地称为id。因此,我将id重命名为name

然后,构造边并使用递归CTE遍历图形。在SQL Server中,这看起来像:

with edges as (
      select distinct t1.id as id1, t2.id as id2
      from temp t1 join
           temp t2
           on (t1.address = t2.address or t1.name = t2.name) and (t1.id <> t2.id)
     ),
     cte as (
      select id, id as next_id, convert(varchar(max), concat(',', id, ',')) as visited, 1 as lev
      from temp
      union all
      select cte.id, e.id2, concat(visited, e.id2, ','), lev + 1
      from cte join
           edges e
           on cte.next_id = e.id1
      where visited not like concat('%,', e.id2, ',%') and lev < 10
     )
select id, min(next_id)
from cte
group by id;

这是一个图形漫游问题。首先,我将重新表述一下数据。这有助于每一行都有一个唯一的标识符,该标识符被恰当地称为id。因此,我将id重命名为name

然后,构造边并使用递归CTE遍历图形。在SQL Server中,这看起来像:

with edges as (
      select distinct t1.id as id1, t2.id as id2
      from temp t1 join
           temp t2
           on (t1.address = t2.address or t1.name = t2.name) and (t1.id <> t2.id)
     ),
     cte as (
      select id, id as next_id, convert(varchar(max), concat(',', id, ',')) as visited, 1 as lev
      from temp
      union all
      select cte.id, e.id2, concat(visited, e.id2, ','), lev + 1
      from cte join
           edges e
           on cte.next_id = e.id1
      where visited not like concat('%,', e.id2, ',%') and lev < 10
     )
select id, min(next_id)
from cte
group by id;

是一个数据库。用你正在使用的数据库标记你的问题。用你正在使用的数据库标记你的问题。谢谢你@gordon linoff这真是太好了!我希望其他人也会觉得这很有帮助。我永远不会知道如何搜索递归CTE或图形遍历。@DevWired。递归CTE非常强大,但也有点棘手。这不是了解它们的最简单的例子,但它是一个很好的例子,说明了为什么你想了解它们。谢谢你@gordon linoff,这非常有效!我希望其他人也会觉得这很有帮助。我永远不会知道如何搜索递归CTE或图形遍历。@DevWired。递归CTE非常强大,但也有点棘手。这不是了解它们的最简单的例子,但它是一个很好的例子,说明了为什么你想了解它们。
with edges as (
      select distinct t1.id as id1, t2.id as id2
      from temp t1 join
           temp t2
           on (t1.address = t2.address or t1.name = t2.name) and (t1.id <> t2.id)
     ),
     cte as (
      select id, id as next_id, convert(varchar(max), concat(',', id, ',')) as visited, 1 as lev
      from temp
      union all
      select cte.id, e.id2, concat(visited, e.id2, ','), lev + 1
      from cte join
           edges e
           on cte.next_id = e.id1
      where visited not like concat('%,', e.id2, ',%') and lev < 10
     )
select id, min(next_id)
from cte
group by id;