【问题标题】:Best method to write a recursive SQL view编写递归 SQL 视图的最佳方法
【发布时间】:2017-02-03 05:19:34
【问题描述】:

我正在寻找最简洁的 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

【问题讨论】:

  • C 不应该显示法国吗?
  • @AdamJacobson 是的 - 谢谢。
  • Canada 也应该与D 一起使用?

标签: sql-server


【解决方案1】:

这是另一种解决方案:

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     

希望这会输出您所期望的结果。
您可以在 Stack Exchange Data 上运行此查询:https://data.stackexchange.com/stackoverflow/query/622821

或者,如果性能出现问题,您可以创建一个单独的表来存储每个国家/地区名称及其唯一字母,这样您就可以进行简单的连接,而不是 LIKEing 来比较事物:

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;

这是对 Stack Exchange 数据的查询: https://data.stackexchange.com/stackoverflow/query/622841

感谢这个字符串拆分的答案:T-SQL Split Word into characters

【讨论】:

    【解决方案2】:

    借助 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,< & >',',')
    

    EDIT - 没有 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
    

    【讨论】:

      猜你喜欢
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多