【问题标题】:SQL - Split string multiple values, multiple valuesSQL - 拆分字符串多个值,多个值
【发布时间】:2019-07-19 21:31:04
【问题描述】:

我希望将一串分隔日期拆分为各自的值,并将它们放在结果表的列中。我在以下方面取得了一些成功,但对于我的特定应用程序来说并不完全 SQL - Split string to columns by multiple delimiters

String (from & to dates)
tblTempDates.tmpString
2019-2-11--2019-2-15,2019-2-20--2019-2-20,2019-2-23--2019-2-23,2019-3-19--2019-3-24

Delimiters
-- seperates from & to
, new record

Output required
tblTempDates2
dtFrom        dtTo
2019-02-11    2019-02-15
2019-02-20    2019-02-20
2019-02-23    2019-02-23
2019-02-19    2019-03-24

在此先感谢 :-)

【问题讨论】:

  • 你真的使用--作为分隔符吗?这是不明智的,因为-- 表示评论
  • 感谢您的评论 - 我并不重视分隔符。

标签: sql tsql sql-server-2014


【解决方案1】:

可以使用while语句来分割csv,

    declare @a table(datefromto varchar(500))

    declare @b table(fromdate varchar(500),todate varchar(500))

    insert into @a values ('2019-2-11--2019-2-15,2019-2-20--2019-2-20,2019-2-23--2019-2-23,2019-3-19--2019-3-24');

    declare @datefromto varchar(500) = (select max(datefromto) from @a)

    declare @datesplit int
    set @datesplit= (SELECT charindex(',',@datefromto))



    WHILE (SELECT charindex(',',@datefromto) FROM @a) <> 0
    BEGIN  



       insert into @b select Left(left(@datefromto,@datesplit),charindex('--',@datefromto)-1) ,
       Right(left(@datefromto,@datesplit-1),charindex('--',@datefromto)-1) from @a


       set @datesplit= (SELECT charindex(',',@datefromto))
       set @datefromto= right(@datefromto,len(@datefromto)-@datesplit)

    END  
       insert into @b select Left(left(@datefromto,@datesplit),charindex('--',@datefromto)-1) ,
       Right(left(@datefromto,@datesplit-1),charindex('--',@datefromto)-1) from @a

    select * from @b

【讨论】:

  • 这部分有效 - 因为它获得了第一个日期和最后一个日期,但两者之间没有任何内容(2019-02-11 ... 2019-03-24) - 所以只有一行
  • 它还省略了将 CSV 拆分为行的步骤;不是一个小步骤。
  • 了解您的问题也涉及逗号分隔列表,我已经用while循环修改了查询,您可以尝试一下。
  • @BigIWT 你能试试这个吗?
  • 嗨,是的,刚才 - 实际上我们快到了。它可以工作,但需要能够处理日和月长度 - 有些是个位数,有些是双数 (2019-1-1) (2019-1-31) (2019-10-1) (2019-10-30) - 提前感谢
【解决方案2】:

如果您的 SQL Server 版本支持,这是使用 STRING_SPLIT 执行此操作的一种好方法:

SELECT
    LEFT(value, CHARINDEX('--', value) - 1) AS dtFrom,
    SUBSTRING(value, CHARINDEX('--', value) + 2, 20) AS dtTo
FROM
(
    SELECT STRING_SPLIT(input, ',')
    FROM yourTable
) t;

这种方法首先使用STRING_SPLIT 将每个从/到日期子字符串以逗号分隔为单独的行。然后,它使用基本字符串函数来隔离起止日期。

【讨论】:

  • 谢谢 - 使用 SQL 2014
  • 那么您将不得不使用其他方法将每个 CSV 值拆分为单独的行。但是,我的外部查询逻辑应该仍然有效。
  • 我有一个类似的 SplitString 函数,当使用您建议的代码时,它会重复吐出相同的日期,而不是每行都被分开。此外,日期 charindex 将根据日/月长度而变化......谢谢
【解决方案3】:

对于STRING_SPLIT()(或OPENJSON)之前的版本,我建议采用这种方法:

DECLARE @tbl TABLE(ID INT IDENTITY, YourString VARCHAR(1000));
INSERT INTO @tbl VALUES('2019-2-11--2019-2-15,2019-2-20--2019-2-20,2019-2-23--2019-2-23,2019-3-19--2019-3-24');

WITH Casted AS
(
    SELECT *
         , CAST('<x><y>' + REPLACE(REPLACE(YourString,'--','</y><y>'),',','</y></x><x><y>') + '</y></x>' AS XML) AsXml
    FROM @tbl 
)
SELECT  ID 
       ,x.value('y[1]','date') AS Date1
       ,x.value('y[2]','date') AS Date2
FROM Casted
CROSS APPLY AsXml.nodes('/x') A(x);

简而言之:

一些字符串替换将您的 multi-level-CSV 转换为这样的 XML

<x>
  <y>2019-2-11</y>
  <y>2019-2-15</y>
</x>
<x>
  <y>2019-2-20</y>
  <y>2019-2-20</y>
</x>
<x>
  <y>2019-2-23</y>
  <y>2019-2-23</y>
</x>
<x>
  <y>2019-3-19</y>
  <y>2019-3-24</y>
</x>

然后我们可以使用.nodes() 将所有重复的&lt;x&gt; 作为派生表。然后我们使用.value() 按他们的位置获取&lt;y&gt;

【讨论】:

    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多