SQL 服务器 - 在插入列之前对组合数字字符串进行排序

SQL Server - Ordering Combined Number Strings Prior To Column Insert

我有 2 个字符串列(数千行),每个字符串中都有有序的数字(每个字符串中可以有零到十个数字)。示例:

+------------------+------------+
|  ColString1      | ColString2 | 
+------------------+------------+
| 1;3;5;12;        | 4;6'       |     
+------------------+------------+
| 1;5;10           | 2;26;      |     
+------------------+------------+
| 4;7;             | 3;         |     
+------------------+------------+

最终结果是合并这两列,对数字进行排序 升序,然后将每个数字放入单独的列(最小,第二小等)。 例如Colstring1 是 1;3;5;12; 而 ColString2 是 4;6; 需要 return 1;3;4;5;6;12; 然后我使用 xml 分配到列中。

使用 xml 一切正常,除了对数字进行排序的步骤(即我得到 1;3;5;12;4;6; 当我组合字符串时,即不按升序排列).
我试过先将它们放入 JSON 数组中进行排序,我想我可以做一个 top[1] 等,但那没有用。 关于如何合并 2 列并在插入列之前对其进行排序的任何帮助:

到目前为止的步骤: 示例数据:

DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, ColString1 VARCHAR(50), ColString2 VARCHAR(50));
INSERT INTO @tbl (ColString1, ColString2)
VALUES
('1;3;5;12;', '4;6;'),
('1;5;10;', '2;26;'),
('14;', '3;8;');

XML 方法(组合字符串并放入列中但顺序不正确):

   ;WITH Split_Numbers (xmlname)
AS
(
    SELECT 
    CONVERT(XML,'<Names><name>'  
    + REPLACE ( LEFT(ColString1+ColString2,LEN(ColString1+ColString2) - 1),';', '</name><name>') + '</name></Names>') AS xmlname
    FROM @tbl
)

 SELECT    
 xmlname.value('/Names[1]/name[1]','int') AS Number1,    
 xmlname.value('/Names[1]/name[2]','int') AS Number2,
 xmlname.value('/Names[1]/name[3]','int') AS Number3,
 xmlname.value('/Names[1]/name[4]','int') AS Number4,
 xmlname.value('/Names[1]/name[5]','int') AS Number5 
--etc for additional columns
 FROM Split_Numbers

当前输出:数字顺序不正确,

+---------+---------+---------+---------+---------+
| Number1 | Number2 | Number3 | Number4 | Number5 |
+---------+---------+---------+---------+---------+
|       1 |       3 |       5 | 12      | 4       |
|       1 |       5 |      10 | 2       | 26      |
|      14 |       3 |       8 | NULL    | NULL    |
+---------+---------+---------+---------+---------+

期望输出:数字按升序排列。

    +---------+---------+---------+---------+---------+
    | Number1 | Number2 | Number3 | Number4 | Number5 |
    +---------+---------+---------+---------+---------+
    |       1 |       3 |       4 | 5       | 6       |
    |       1 |       2 |       5 | 10      | 26      |
    |      3  |       8 |      14 | NULL    | NULL    |
    +---------+---------+---------+---------+---------+

JSON 方法:将列组合成一个 JSON 数组,但在 JSON 格式时我仍然无法正确排序。

REPLACE ( CONCAT('[',   LEFT(ColString1+ColString2,LEN(ColString1+ColString2) - 1), ']') ,';',',')

如果有任何方法可以在输入前订购 xml 或 JSON 字符串,我们将不胜感激。如果有更简单的解决方案,很乐意考虑替代方法。

您可以使用 string_agg()string_split():

select t.*, newstring
from t cross apply
     (select string_agg(value, ',') order by (value) as newstring
      from (select s1.value
            from unnest(colstring1, ',') s1
            union all
            select s2.value
            from unnest(colstring2, ',') s2
           ) s
     ) s;

也就是说,您可能应该努力修复数据模型。在字符串中存储数字是不好的。在一个字符串中存储多个值是非常糟糕的。如果数字是对其他表的外国引用,那就是坏坏坏坏坏坏

在等待 DDL 和示例数据填充等期间,这里有一个概念性的例子供您参考。它使用 XQuery 及其 FLWOR 表达式。

CTE 完成了大部分繁重的工作:

  • 将两列值连接成一个字符串。 CONCAT() 函数防止 NULL 值。
  • 将其转换为 XML 数据类型。
  • 通过将元素的值转换为 FLWOR 表达式中的 int 数据类型,对 XML 元素进行排序。
  • 过滤掉 XML 个没有合法值的元素。

其余的都是微不足道的。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, col1 VARCHAR(100), col2 VARCHAR(100));
INSERT INTO @tbl (col1, col2)
VALUES
('1;3;5;12;', '4;6;'),
('1;5;10;', '2;26;');
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = ';';

;WITH rs AS
(
    SELECT *
          , CAST('<root><r><![CDATA[' + 
               REPLACE(CONCAT(col1, col2), @separator, ']]></r><r><![CDATA[') + 
             ']]></r></root>' AS XML).query('<root>
                    {
                        for $x in /root/r[text()]
                        order by xs:int($x)
                        return $x
                    }
                    </root>') AS sortedXML
    FROM @tbl
)
SELECT ID
    , c.value('(r[1]/text())[1]','INT') AS Number1
    , c.value('(r[2]/text())[1]','INT') AS Number2
    , c.value('(r[3]/text())[1]','INT') AS Number3
    -- continue with the rest of the columns
FROM rs CROSS APPLY sortedXML.nodes('/root') AS t(c);

输出

+----+---------+---------+---------+
| ID | Number1 | Number2 | Number3 |
+----+---------+---------+---------+
|  1 |       1 |       3 |       4 |
|  2 |       1 |       2 |       5 |
+----+---------+---------+---------+