【问题标题】:SQL how to join multiple selects in columns versus rowsSQL如何在列与行中加入多个选择
【发布时间】:2019-09-10 22:13:03
【问题描述】:

我有以下SQL Server 查询:

DECLARE @data1 nvarchar(500) = '0.2,0.3,0.4'
DECLARE @data2 nvarchar(500) = '0.6,0.7,0.8'
DECLARE @data3 nvarchar(500) = '0.3,0.5,0.5'


SELECT * FROM STRING_SPLIT ( @data1 , ',' ) 
UNION ALL
SELECT * FROM STRING_SPLIT ( @data2 , ',' ) 
UNION ALL
SELECT * FROM STRING_SPLIT ( @data3 , ',' ) 

结果如下:

我需要的是data1 是第一列,data2 是第二列,data3 是第三列。对于每个数据选择,我将始终拥有相同数量的记录。

有什么线索吗?谢谢

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    SQL Server 不保证来自string_split() 的结果的顺序。唉,唉。

    因此,我推荐使用递归 CTE:

    with cte as (
          select convert(nvarchar(max), null) as str, convert(nvarchar(max), v.rest) as rest, v.which, 0 as lev
          from (values (@data1, 1), (@data2, 2), (@data3, 3)) v(rest, which)
          union all
          select convert(nvarchar(max), left(rest, charindex(',', rest + ',') - 1)),
                 convert(nvarchar(max), stuff(rest, 1, charindex(',', rest + ','), '')) as rest,
                 which, lev + 1
          from cte
          where rest <> ''
         )
    select max(case when which = 1 then str end) as str1,
           max(case when which = 2 then str end) as str2,
           max(case when which = 3 then str end) as str3
    from cte
    where lev > 0
    group by lev;
    

    Here 是一个 dbfiddle。

    未来,他们有望添加其他数据库中可用的with offset/with ordinality 选项。

    【讨论】:

    • 非常感谢戈登
    【解决方案2】:

    UNION 确实不是你需要的。我猜CROSS JOIN 也不是您需要的,因为它会生成所有 3 个数据集的笛卡尔积,这里会生成 3^3 = 27 条记录。

    你确实需要某种JOIN。但是我们在使用STRING_SPLIT 时必须小心,因为它基本上返回无序记录,如the documentation 中所述:

    输出行可以是任意顺序。不保证顺序与输入字符串中子字符串的顺序相匹配。

    这是一种解决方案,它按值对每个记录集进行排序,然后按行数连接结果。结果,您只得到 3 条记录,我相信这就是您想要的,并且具有可预测的顺序:

    SELECT x1.value, x2.value, x3.value
    FROM 
        (
            SELECT value, ROW_NUMBER() OVER(ORDER BY value) rn FROM STRING_SPLIT ( @data1, ',' )
        ) x1
        INNER JOIN (
            SELECT value, ROW_NUMBER() OVER(ORDER BY value) rn FROM STRING_SPLIT ( @data2, ',' )
        ) x2 ON x2.rn = x1.rn
        INNER JOIN (
            SELECT value, ROW_NUMBER() OVER(ORDER BY value) rn FROM STRING_SPLIT ( @data2, ',' )
        ) x3 ON x3.rn = x1.rn
    

    demo on DB Fiddle 与您的示例数据返回:

    value | value | value
    :---- | :---- | :----
    0.2   | 0.6   | 0.6  
    0.3   | 0.7   | 0.7  
    0.4   | 0.8   | 0.8 
    

    【讨论】:

      【解决方案3】:

      你想要的不是UNION

          SELECT * FROM STRING_SPLIT ( @data1 , ',' ) as Data1,
          STRING_SPLIT ( @data2 , ',' ) as Data2,
          STRING_SPLIT ( @data3 , ',' ) as Data3
      
      

      【讨论】:

        【解决方案4】:

        另一种可能的解决方案:

        DECLARE @data1 nvarchar(500) = '0.2,0.3,0.4'
        DECLARE @data2 nvarchar(500) = '0.6,0.7,0.8'
        DECLARE @data3 nvarchar(500) = '0.3,0.5,0.5'
        
        ;with cte1(data, rn) as
        (
        select value, row_number() over(order by (select null)) as rn
        from STRING_SPLIT(@data1, ',')
        ),
        cte2(data, rn) as
        (
        select value, row_number() over(order by (select null)) as rn
        from STRING_SPLIT(@data2, ',')
        ),
        cte3(data, rn) as
        (
        select value, row_number() over(order by (select null)) as rn
        from STRING_SPLIT(@data3, ',')
        )
        select t1.data as Data1, t2.data as Data2, t3.data as Data3
        from cte1 t1
        join cte2 t2 on t2.rn = t1.rn
        join cte3 t3 on t3.rn = t1.rn
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-14
          • 1970-01-01
          相关资源
          最近更新 更多