2016-09-15 86 views
1

我正在从完全基于光标的基础集合移动一堆代码并生成这一直在做我的头。我们创建一个6字符的短代码(唯一)插入到每个公司数据库和我(想)在游标之外实现这一点。的我在迄今为止其中生成唯一标识符作为基于集合的查询

例子:

CREATE TABLE #customers (name VARCHAR(50), shortname VARCHAR(10)) 
INSERT INTO #customers VALUES 
('Michael Smith', 'Michae') 
,('Michael Douglas', 'Mich_1') 
,('Michael Yang', 'Mich_2') 

CREATE TABLE #newcustomers (name VARCHAR(50), shortname VARCHAR(10) NULL) 
INSERT INTO #newcustomers (name) VALUES 
('Michael Black') 
,('Michael White') 

SELECT * FROM #customers 
SELECT * FROM #newcustomers 

DECLARE @shortname VARCHAR(10) 
DECLARE @iteration INT = 0 

WHILE EXISTS(SELECT shortname FROM #customers WHERE shortname = @shortname) 
BEGIN 
    SELECT @shortname = LEFT(name, 6) FROM #newcustomers 

    UPDATE #newcustomers SET shortname = @shortname 

    SET @shortname = LEFT(@shortname, 4) + '_' + @iteration 

    SET @iteration = @iteration + 1 
END 

希望的例子是在查明我试图去,有什么建议或例子将是非常有益足够了。我的例子不起作用。

+1

正如一个音符,一个'WHILE'也将作为游标执行。它将使用相同的实现,它只是作为“WHILE”被“屏蔽”。 –

+0

'Micahel Douglas'有一个错字... – Shnugo

+0

顺便说一句:这是一个很好的问题,尤其是copy'n'pasteable测试场景很棒,自己的努力,清晰的解释......值得+1 – Shnugo

回答

2

试试这个

你的表作为实物模型

CREATE TABLE #customers (ID INT IDENTITY, name VARCHAR(50), shortname VARCHAR(10)) 
INSERT INTO #customers VALUES 
('Michael Smith', 'Michae') 
,('Michael Douglas', 'Mich_1') 
,('Michael Yang', 'Mich_3') 
,('Testman', 'Testma') 
,('Testman1', 'Test_1'); 

CREATE TABLE #newcustomers (ID INT IDENTITY,name VARCHAR(50), shortname VARCHAR(10) NULL) 
INSERT INTO #newcustomers (name) VALUES 
('Michael Black') 
,('Michael White') 
,('Testman2') 
,('Someone new'); 

--This CTE将结合现有的所有名称

WITH AllNames AS 
(
    SELECT '1_old' AS datasource,ID,name,shortname FROM #customers 
    UNION ALL SELECT '2_new',ID,name,shortname FROM #newcustomers 
) 

--This CTE将使用组合列表并计算出正确的“索引”

,ShortNames AS 
(
    SELECT c.* 
      ,A.First6 
      ,ROW_NUMBER() OVER(PARTITION BY A.First6 ORDER BY datasource,ID) AS NrTotal 
      ,ROW_NUMBER() OVER(PARTITION BY datasource,A.First6 ORDER BY datasource,ID) AS Nr 
      ,CASE WHEN ISNUMERIC(SUBSTRING(shortname+'  ',6,10))=1 
       THEN CAST(SUBSTRING(shortname+'  ',6,10) AS INT) ELSE 0 END AS ExistIndex 
    FROM AllNames AS c 
    CROSS APPLY(SELECT LEFT(name + '  ',6)) AS A(First6) 
) 

- 所有新的与NrTotal = 1获得6个字母的是,所有其他的景气指数

SELECT * 
     ,CASE WHEN datasource='1_old' THEN shortname ELSE 
     CASE WHEN datasource='2_new' AND NrTotal=1 THEN First6 
      ELSE LEFT(First6,4) + '_' + CAST(Nr + (SELECT ISNULL(MAX(x.ExistIndex),1) 
                 FROM ShortNames AS x 
                 WHERE x.First6=ShortNames.First6) AS VARCHAR(5)) 
     END 
     END 
FROM ShortNames 

GO 
DROP TABLE #customers; 
DROP TABLE #newcustomers; 

结果

+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| datasource | ID | name   | shortname | First6 | NrTotal | Nr | ExistIndex | (Kein Spaltenname) | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 1_old  | 1 | Michael Smith | Michae | Michae | 1  | 1 | 0   | Michae    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 1_old  | 2 | Michael Douglas | Mich_1 | Michae | 2  | 2 | 1   | Mich_1    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 1_old  | 3 | Michael Yang | Mich_3 | Michae | 3  | 3 | 3   | Mich_3    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 1_old  | 4 | Testman   | Testma | Testma | 1  | 1 | 0   | Testma    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 1_old  | 5 | Testman1  | Test_1 | Testma | 2  | 2 | 1   | Test_1    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 2_new  | 1 | Michael Black | NULL  | Michae | 4  | 1 | 0   | Mich_4    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 2_new  | 2 | Michael White | NULL  | Michae | 5  | 2 | 0   | Mich_5    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 2_new  | 4 | Someone new  | NULL  | Someon | 1  | 1 | 0   | Someon    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
| 2_new  | 3 | Testman2  | NULL  | Testma | 3  | 1 | 0   | Test_2    | 
+------------+----+-----------------+-----------+--------+---------+----+------------+--------------------+ 
+0

这真是太棒了!我敬畏先生!唯一没有考虑到的是,例如,如果您有'Mich_2'(将Michael Yang更改为'Mich_3')丢失,并且您运行此操作,那么会有一个副本,因为它正在运行ROW_NUMBER。实际上,它完全忽略了每次运行时重新发布数字的原始增量 –

+0

@BrianRamsey,查看我的更新 – Shnugo

+0

令人惊叹......无语......我实际上试图用你的原始代码完成同样的事情,和你一样快。我无法感谢您的努力。谢谢! –

0

一种选择是使用computed column

沿着这些线路的表设计将工作:

- Sample table. 
DECLARE @Sample TABLE 
    (
     Id   INT IDENTITY(1, 1), 
     FullName VARCHAR(255), 
     ShortName AS LEFT(FullName, 4) + '_' + CAST(Id AS VARCHAR(255)) 
    ) 
; 

-- Add set containing two companies. 
INSERT INTO @Sample 
    (
     FullName 
    ) 
VALUES 
    ('ABC LTD'), 
    ('XYZ PLC') 
; 

返回

Id FullName ShortName 
1 ABC LTD  ABC _1 
2 XYZ PLC  XYZ _1 

IdShortName列将通过SQL Server管理。您只需要添加FullName

编辑

使用表变量,以使其更容易发挥沿

返工例子。

+0

不幸的是这种方法会做'ABC _1,XYZ _2',由于当前的系统行为,我需要它们是'ABC _1,XYZ _1'。也由于目前的行为,第一个条目应该总是从左6。 –

+0

啊,我明白了。您可以将@RaduGheorghiu解决方案与[窗口行数](https://msdn.microsoft.com/en-GB/library/ms186734.aspx?f=255&MSPPError=-2147217396)结合使用。 –