Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.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 server 如何将列对值的并集转换为线性表?_Sql Server_Sql Server 2005_Tsql - Fatal编程技术网

Sql server 如何将列对值的并集转换为线性表?

Sql server 如何将列对值的并集转换为线性表?,sql-server,sql-server-2005,tsql,Sql Server,Sql Server 2005,Tsql,问题 我们有一个重复客户编号表: A varchar(16) NOT NULL, B varchar(16) NOT NULL 这些列一开始是旧列和新列(删除和保留),但后来被转移到两者都不可取的地方。列实际上只是“A”和“B”——同一客户的两个数字,可以任意顺序排列 此外,对于同一客户,表可以有任意数量的对。您可能会看到像这样的行 a,b b,c a,b b,a c,a 也就是说,a、b、c都是为同一个客户提供的。您可能还会看到像这样的行 a,b b,c a,b b,a c,a 意思

问题

我们有一个重复客户编号表:

A varchar(16) NOT NULL,
B varchar(16) NOT NULL
这些列一开始是旧列和新列(删除和保留),但后来被转移到两者都不可取的地方。列实际上只是“A”和“B”——同一客户的两个数字,可以任意顺序排列

此外,对于同一客户,表可以有任意数量的对。您可能会看到像这样的行

a,b
b,c
a,b
b,a
c,a
也就是说,a、b、c都是为同一个客户提供的。您可能还会看到像这样的行

a,b
b,c
a,b
b,a
c,a
意思是a、b、c都是同一个客户

它不像“旧”和“新”值那样是一种干净的非循环表示。客户的客户ID列表在此表中以一行或多行的块表示,其中唯一的连接是一行中a或B列的值可能显示在其他行的a或B列中。我的任务是将它们全部绑定到每个客户的列表中

我想把这些乱七八糟的东西变成

MasterKey int NOT NULL,
CustNum varchar(16) NOT NULL UNIQUE,
PRIMARY KEY( MasterKey, CustNum )
客户的一个或多个数字将共享此表中的主密钥。正如惟一约束所说,给定的CustNum不能出现多次

例如,像这样的行来自原始

1a,1b
1b,1c
2a,2b
2b,2c
2d,2a
...
在新表中应该以这样的行结束

1 1a
1 1b
1 1c
2 2a
2 2b
2 2c
2 2d
...
编辑:上面的值只是为了使图案清晰。实际的客户编号值是任意的
varchar
s

我尝试的解决方案

这感觉像是递归的工作,因此是CTE。但是源数据的潜在循环性质使得我很难得到锚的情况。我试着把它预先清理成一种非循环的形式,但我似乎仍然不能正确地做到这一点

我还固执地尝试将其作为基于集合的SQL操作来执行,而不是使用游标和循环。但也许那是不可能的


我花了整整8个小时思考这个问题,并尝试不同的方法,但它一直在溜走。关于正确方法的任何想法或建议,甚至一些示例代码?

在我看来,这是工会的工作。下面的代码假设不能在同一条记录中包含1a和2b

创建表#temp(a varchar(10),b varchar(10))

给定输入数据:

a,b
b,c
d,e
e,f
g,d
我将添加两个新表,一个包含pk值,另一个包含pk和与pks的一对多关系中的重复值,如下所示:

pk
a
b
c
d
e
f
g


pk dup
a   b   
b   a
b   c
c   b   
d   e
e   d
e   f
f   e   
g   d
d   g
pk/dup表中的行由输入文件填充,pks和重复项按(pk,dup)顺序和(dup,pk)顺序插入

这将获得键和重复项之间的第一组关系,但需要再次迭代该组以获得间接关系,如“c是a的重复项”

您可以通过自连接pkdup1.dup=pkdup2.pk上的pk/dup表来获得这些关系。这将行(a,b)与行(b,a)和(b,c)连接起来,从而允许您识别关系(a,c)。它还将拾取(d,f)(f,d)(g,e)。您需要重复迭代以获取(g,f)


HTH

找到钥匙的模式是什么?如果它只是字符串中的第一个数字,则会将其拉出:

select substring('FOO12',patindex('%[0-9]%','FOO12'),100)
select substring('12FOO',1,patindex('%[A-Z]%','12FOO')-1)
如果以数字开头,则会将其拉出:

select substring('FOO12',patindex('%[0-9]%','FOO12'),100)
select substring('12FOO',1,patindex('%[A-Z]%','12FOO')-1)

两者都返回12。

我认为您必须进行一些循环。在这里,我一次查看一行,以确保获得属于单个主键的所有链接值

while (1=1)
begin

    -- get the next key that is not inserted yet as MasterKey or key
    select top 1 @masterKey = a
    from myTable 
    where not exists (select 1
        from #temp
        where #temp.MasterKey = myTable.a
        or #temp.Key = myTable.a)

    if(@masterKey is null) -- out of a's so now work the b's
        select top 1 @masterKey = b
        from myTable 
        where not exists (select 1
            from #temp
            where #temp.MasterKey = myTable.b
            or #temp.Key = myTable.b)

    if(@masterKey is null) -- totally done.
        break

    insert into #temp
    (masterKey, key)
    values(@masterKey, @masterKey)


    while (1=1) -- now insert anything new with this masterKey in a
    begin
        insert into #temp
        select top 1 @masterKey, myTable.b
        from myTable
        where myTable.a = @masterKey
        not exists (select 1
        from #temp
        where #temp.MasterKey = myTable.b
        or #temp.Key = myTable.b))

        if @@rowcount < 1
            break
    end 


    while (1=1) -- now insert anything with this masterKey in b
    begin
        insert into #temp
        select top 1 @masterKey, myTable.a
        from myTable
        where myTable.b = @masterKey
        not exists (select 1
        from #temp
        where #temp.MasterKey = myTable.a
        or #temp.Key = myTable.a))

        if @@rowcount < 1
            break

    end 

end
while(1=1)
开始
--获取下一个尚未作为主密钥或密钥插入的密钥
选择top 1@masterKey=a
从myTable
不存在的位置(选择1
从#temp
其中#temp.MasterKey=myTable.a
或#temp.Key=myTable.a)
如果(@masterKey为null)--从a中取出,那么现在就工作b
选择top 1@masterKey=b
从myTable
不存在的位置(选择1
从#temp
其中#temp.MasterKey=myTable.b
或#temp.Key=myTable.b)
如果(@masterKey为空)--完全完成。
打破
插入#temp
(万能钥匙,钥匙)
值(@masterKey,@masterKey)
while(1=1)--现在在
开始
插入#temp
在masterKey,myTable.b中选择top 1
从myTable
其中myTable.a=@masterKey
不存在(选择1
从#temp
其中#temp.MasterKey=myTable.b
或#temp.Key=myTable.b))
如果@@rowcount<1
打破
结束
while(1=1)--现在在b中插入具有此主密钥的任何内容
开始
插入#temp
在masterKey,myTable.a中选择top 1
从myTable
其中myTable.b=@masterKey
不存在(选择1
从#temp
其中#temp.MasterKey=myTable.a
或#temp.Key=myTable.a))
如果@@rowcount<1
打破
结束
结束

实际上,您必须将2个insert部分包装到另一个循环中,以确保在获取下一个masterKey之前它已耗尽,但您明白了

根据评论中的一些样本数据,我认为这应该可以做到吗

CREATE TABLE #sample
(A NVARCHAR(50)
,B NVARCHAR(50))

INSERT INTO #sample VALUES('FOO12','12DEF')
INSERT INTO #sample VALUES('12GHJ','12ABC')
INSERT INTO #sample VALUES('GURGLE721','GURGLZ721')
INSERT INTO #sample VALUES('word21','book721')
INSERT INTO #sample VALUES('orange21','apple21')

;WITH CTE as
(
SELECT A
,PATINDEX('%[A-Za-z]%',A) as text_start
,PATINDEX('%[0-9]%',A) as num_start
FROM #sample
UNION ALL
SELECT B
,PATINDEX('%[A-Za-z]%',B) as text_start
,PATINDEX('%[0-9]%',B) as num_start
FROM #sample
)
,cte2 AS
(
SELECT
*
,CASE WHEN text_start > num_start --Letters after numbers
    THEN SUBSTRING(A,text_start - num_start + 1,99999)
    WHEN text_start = 1 --Letters at start of string
    THEN SUBSTRING(A,1,num_start - 1)
    END AS letters
,CASE WHEN num_start > text_start --Numbers after letters
    THEN SUBSTRING(A,num_start - text_start + 1,99999)
    WHEN num_start = 1 --Numbers at start of string
    THEN SUBSTRING(A,1,text_start- 1)
    END AS numbers
FROM cte
)
SELECT DISTINCT
DENSE_RANK() OVER (ORDER BY numbers ASC) as group_num
,numbers + letters as cust_details
FROM cte2
ORDER BY numbers + letters asc

我将做一些我以前没有做过的事情,并发布一个答案 我自己的问题。我要向Beth和JBrooks表示深深的感谢 感谢你把我带向正确的方向。我真的很想解决这个问题 以基于集合的声明方式。也许这仍然是可能的使用 CTE和递归。但有一次我投降了,我说可以 必须是命令式的和迭代式的,这样做要容易得多

无论如何,根据我的问题中的目标表:

CREATE TABLE UniqueCustomers
(
    uid     int NOT NULL,
    gpid    varchar(16) NOT NULL UNIQUE, -- Important: UNIQUE to disallow duplicates
    PRIMARY KEY( uid, gpid ) -- Important: Disallow duplicates
)
我提出了以下存储过程。它可以在 一个接一个地报告新的重复。它也可以在循环中调用 在以随机方式成对存储重复项的旧表上 秩序

创建过程报告DuplicateCustomerID
(
@id1 varchar(16),
@id2 varchar(16)
)
作为
开始
如果@id1@id2
开始
--检索以下各项的uid(如果有)