简体   繁体   English

使用T-SQL动态设置唯一值而无循环

[英]Set unique value dynamically without loop using T-SQL

I need to join a table to itself on either of two values. 我需要在两个值之一上将表联接到自身。 I can do this easily enough with an OR in the join. 使用OR中的OR可以很容易地做到这一点。 However, I am trying to create a table to house this data to make it easier as I add new records daily. 但是,我试图创建一个表来容纳这些数据,以使其在每天添加新记录时变得更容易。 I want to create a table to hold this data, and keep a unique value for each result. 我想创建一个表来保存此数据,并为每个结果保留唯一的值。

I have a working example below, but it uses a while loop and is extremely slow. 我在下面有一个工作示例,但是它使用while循环,并且速度非常慢。 I would like to convert this to a set-based operation, but keep coming up short. 我想将其转换为基于集合的操作,但请保持简短。

Table @t is the source of the data. @t是数据源。 Table @hh is the new table to hold the unique value ( hhid ). Table @hh是保存唯一值( hhid )的新表。

Example: 例:

declare @t table (appid int, phone varchar(10), bcn varchar(10));
declare @hh table (bcn varchar(10), hhid int default(null));

insert @t 
      select 1, '1115551212','1'
union select 2, '1115551212','1'
union select 3, '1115551212','2'
union select 4, '9995551212','2'
union select 5, '8885551212','3'
union select 6, '1115551212','4'
union select 7, '1115551212','5'
union select 8, '7775551212','1'
union select 9, '7785551212','6'
union select 10, '7795551212','6'

insert @hh select distinct bcn,null from @t;

DECLARE @hhid int = -1;
DECLARE @bcn varchar(10);

SELECT TOP(1) @bcn =  bcn FROM @hh WHERE hhid is null;
SELECT @hhid = ISNULL((SELECT MAX(isnull(hhid,-1)) FROM @hh),-1);
if @hhid = -1
        SET @hhid = 4999999;
WHILE @bcn is not null
BEGIN
    SET @hhid += 1;

    UPDATE @hh SET hhid = @hhid WHERE bcn in (
    select distinct t2.bcn
    FROM @hh h
    JOIN @t t on h.bcn = t.bcn
    left join @t t2 on t.phone = t2.phone
    WHERE h.bcn = @bcn and t.phone <> '');

    SET @bcn = null;
    SELECT top(1) @bcn =  bcn from @hh where hhid is null;
END

select * from @hh

EDIT: Expected Results (as returned by the code): 编辑:预期结果(由代码返回):

BCN  HHID  
 1   5000000  
 2   5000000  
 3   5000001  
 4   5000000  
 5   5000000  
 6   5000002

From the output, you can see that all records that share either a BCN or PHONE value get the same HHID, and those that do not share anything in common with others get their own unique ID. 从输出中,您可以看到所有共享BCN或PHONE值的记录都具有相同的HHID,而那些与其他共享不共享内容的记录则具有自己的唯一ID。 As I said, this code works, and does what I need, but I want to try to replace it with set-based operations. 就像我说的那样,这段代码可以工作,并且可以满足我的需要,但是我想尝试将其替换为基于集合的操作。

This script does it without loop/cursor. 该脚本可以不使用循环/光标。 It creates two indexes that are important to speed up the query: t_phone_ind and t_bcn_ind . 它创建两个对加快查询速度很重要的索引: t_phone_indt_bcn_ind You can check the actual execution plan, you'll see they are both being used to speed up the query. 您可以检查实际的执行计划,您会看到它们都被用来加快查询速度。

CREATE TABLE #t(appid INT PRIMARY KEY, phone VARCHAR(10), bcn VARCHAR(10));
CREATE NONCLUSTERED INDEX t_phone_ind ON #t(phone,bcn); -- for bcn->MIN(phone)
CREATE NONCLUSTERED INDEX t_bcn_ind ON #t(bcn,phone);   -- for phone->MIN(bcn)
insert #t(appid,phone,bcn) 
      select 1, '1115551212','1'
union select 2, '1115551212','1'
union select 3, '1115551212','2'
union select 4, '9995551212','2'
union select 5, '8885551212','3'
union select 6, '1115551212','4'
union select 7, '1115551212','5'
union select 8, '7775551212','1'
union select 9, '7785551212','6'
union select 10, '7795551212','6';

;WITH cte1 AS (
    SELECT bcn,MIN(phone) AS phone FROM #t GROUP BY bcn 
),
cte2 AS (
    SELECT phone,MIN(bcn) AS bcn FROM #t GROUP BY phone
)
SELECT
    cte1.bcn,
    hhid=4999999+DENSE_RANK() OVER (ORDER BY cte2.bcn)
FROM
    cte1
    LEFT JOIN cte2 ON
        cte2.phone=cte1.phone
ORDER BY
    cte1.bcn;

DROP TABLE #t;

Result: 结果:

+-----+---------+
| bcn |  hhid   |
+-----+---------+
|   1 | 5000000 |
|   2 | 5000000 |
|   3 | 5000001 |
|   4 | 5000000 |
|   5 | 5000000 |
|   6 | 5000002 |
+-----+---------+

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM