编写递归SQL视图的最佳方法

时间:2017-02-02 20:36:15

标签: sql-server

我正在寻找最干净的SQL查询来实现以下目标。性能不是那么重要,因为我的数据集很小。

Sample table:
Letter field holding: A, B, C, D, E,
Location field holding: UAE, CANADA, BOSTON, BAHRAIN, FRANCE

我正在寻找一个结果,列出其中包含字母组合的每个字母/位置,因此结果如下:

A-UAE
A-CANADA
A-BAHRAIN
A-FRANCE
B-BOSTON
B-BAHRAIN
C-CANADA
C-FRANCE
D-CANADA
E-UAE
E-FRANCE

2 个答案:

答案 0 :(得分:2)

这是另一种解决方案:

DECLARE @Letter TABLE (
  letter CHAR(1) PRIMARY KEY
  );

DECLARE @Country TABLE (
  name VARCHAR(100) PRIMARY KEY
  );

INSERT INTO @Letter (letter)
VALUES ('A'), ('B'), ('C'), ('D'), ('E');

INSERT INTO @Country (name)
VALUES ('UAE'), ('CANADA'), ('BOSTON'), ('BAHRAIN'), ('FRANCE');

SELECT CONCAT(L.letter, ' - ', C.name)
FROM @Letter AS L
INNER JOIN @Country AS C
  ON C.name LIKE '%' + L.letter + '%'
ORDER BY L.letter, C.name;

结果:

A - BAHRAIN 
A - CANADA  
A - FRANCE  
A - UAE     
B - BAHRAIN 
B - BOSTON  
C - CANADA  
C - FRANCE  
D - CANADA  
E - FRANCE  
E - UAE     

希望你输出你期望的东西 您可以在堆栈交换数据上运行此查询:https://data.stackexchange.com/stackoverflow/query/622821

或者,如果性能出现问题,您可以创建一个单独的表格,用于存储每个国家/地区名称及其名称。唯一的字母,所以你可以做一个简单的连接,而不是LIKE来比较事情:

DECLARE @CountrySplit TABLE (
  letter CHAR(1)
  , name VARCHAR(100)
  , PRIMARY KEY (letter, name)
  );

INSERT INTO @CountrySplit (letter, name)
SELECT DISTINCT SUBSTRING(C.name, v.number + 1, 1), C.name
FROM @Country AS C
INNER JOIN master..spt_values AS V
    ON V.number < LEN(C.name)
WHERE V.type = 'P';

SELECT CONCAT(L.letter, ' - ', CS.name) AS Result
FROM @CountrySplit AS CS
INNER JOIN @Letter AS L
    ON L.letter = CS.letter;

这是对堆栈交换数据的查询: https://data.stackexchange.com/stackoverflow/query/622841

对此字符串拆分答案的肯定:T-SQL Split Word into characters

答案 1 :(得分:1)

借助Parse / Split UDF和Cross Apply。

我添加了一个ID来证明可以为整个表运行

示例

Declare @YourTable table (ID int,Letter varchar(50),Location varchar(50))
Insert Into @YourTable values
(1,'A, B, C, D, E,','UAE, CANADA, BOSTON, BAHRAIN, FRANCE')

Select A.ID
      ,B.*
 From  @YourTable A
 Cross Apply (
                Select NewValue = B1.RetVal+'-'+B2.RetVal 
                  From [dbo].[udf-Str-Parse](A.Letter,',') B1
                  Join [dbo].[udf-Str-Parse](A.Location,',') B2
                    on  charindex(B1.RetVal,B2.RetVal)>0
             ) B

<强>返回

ID  NewValue
1   A-UAE
1   A-CANADA
1   A-BAHRAIN
1   A-FRANCE
1   B-BOSTON
1   B-BAHRAIN
1   C-CANADA
1   C-FRANCE
1   D-CANADA
1   E-UAE
1   E-FRANCE

UDF(如果需要)

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From  (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--Thanks Shnugo for making this XML safe
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--Select * from [dbo].[udf-Str-Parse]('this,is,<test>,for,< & >',',')

编辑 - 没有UDF的选项

Declare @YourTable table (ID int,Letter varchar(50),Location varchar(50))
Insert Into @YourTable values
(1,'A, B, C, D, E,','UAE, CANADA, BOSTON, BAHRAIN, FRANCE')

Select A.ID
      ,B.*
 From  @YourTable A
 Cross Apply (
                Select NewValue = B1.RetVal+'-'+B2.RetVal 
                  From (
                        Select RetSeq = Row_Number() over (Order By (Select null))
                              ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                        From  (Select x = Cast('<x>' + replace((Select replace(A.Letter,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                       ) B1
                  Join (
                        Select RetSeq = Row_Number() over (Order By (Select null))
                              ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                        From  (Select x = Cast('<x>' + replace((Select replace(A.Location,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                       ) B2
                    on  charindex(B1.RetVal,B2.RetVal)>0
             ) B