从格式 yyyy_d_m

问题描述

sql Server 中,我有一列包含格式为 yyyy_d_m_(randominteger)_(randominteger)_blahblahblah 字符串的字符串。

所以

2021_28_6_42_blahblahblahblah
2021_8_12_17_4_blahblahblahblah

我需要检索第三个下划线之前的所有内容并将其转换为日期。

我已经尝试在以下方面使用变体:

SELECT
left(column,patindex('%[^0-9]%',column))

然而,尾随整数的长度是不同的。日期和月份也是如此,因为它们没有输入零。我也遇到了下划线作为通配符的问题。

解决方法

DECLARE @text VARCHAR(200) = '2021_8_12_17_4_blahblahblahblah';

-- https://stackoverflow.com/questions/8726111/sql-server-find-nth-occurrence-in-a-string
with T as (
    select 0 as row,charindex('_',@text) pos,@text as txt,1 as occurance
    union all
    select pos + 1,@text,pos + 1),occurance+1
    from T
    where pos > 0
)
select 
    @text,pos,occurance,substring(@text,pos) as "DATE"
from T 
where occurance=3
  • 首先我声明一个变量(名为 @text
  • 在 stackoverflow 的帮助下,该链接是使用 Google 的结果之一:对于 tsl find character in string,还有一些小改动

结果:

                                  pos         occurance   DATE
--------------------------------- ----------- ----------- ------------
2021_8_12_17_4_blahblahblahblah   10          3           2021_8_12

其中 DATE 下的列是您要查找的文本。

附言用这段代码创建一个函数会更漂亮,但是......?

,

为了简洁起见,计算 CROSS APPLY 中前两个下划线的位置。

select datefromparts(substring(t.d,1,i1 - 1),substring(t.d,i2 + 1,t.d,i2 + 1) - i2 - 1),i1 + 1,i2 - i1 - 1)
                     ) dt
from (
       values 
       ('2021_8_12_17_4_blahblahblahblah'),('2021_28_6_42_blahblahblahblah')       
     ) t(d) -- your table here
cross apply( 
       select charindex('_',1) i1,1) + 1) i2
     ) t2
,

另一种带有一点 JSON 的选项

Select A.*,AsDate = datefromparts(JSON_VALUE(S,'$[0]'),JSON_VALUE(S,'$[2]'),'$[1]')
                             )
From YourTable A
Cross Apply ( values ( '["'+replace([column],'_','","')+'"]' ) ) B(S)

结果

column                          AsDate
2021_28_6_42_blahblahblahblah   2021-06-28
2021_8_12_17_4_blahblahblahblah 2021-12-08

注意: 如果您的字符串中碰巧有双引号等,则可能需要应用 string_escape()

...
Cross Apply ( values ( '["'+replace(STRING_ESCAPE([column],'json'),"')+'"]' ) ) B(S)
,

这是一个非常糟糕的设计。您仍然可以将其转换为日期,但如果性能是一个问题,那么我将使用 CLR 函数。

create table baddata (bad varchar(100));
insert into baddata (bad) values 
('2021_28_6_42_blahblahblahblah'),('2021_8_12_17_4_blahblahblahblah');

with bd (bad,v,rn) as
(
  select bad,cast(v as int),row_number() over (partition by bad order by bad)
  from baddata
  cross apply (select top(3) value 
          from string_split(baddata.bad,'_')) t(v)
),ydm (bad,y,d,m) as
(
  select bad,sum(cast(case when rn=1 then v end as int)) y,sum(cast(case when rn=2 then v end as int)) d,sum(cast(case when rn=3 then v end as int)) m
  from bd
  group by bad
)
select bad,datefromparts(y,m,d) [date]
from ydm;
,

您需要计算前 3 个位置中下划线的位置。以下工作通过连续 CROSS APPLY'ing 获得 CHARINDEX 位置。像这样

void Update()
  {
      movement = Input.GetAxis("Horizontal");
      if (((transform.localScale.x > 0 && movement < 0) ||
      (transform.localScale.x < 0 && movement > 0))
      && !isTurning)
      {
        isTurning = true;
        turningCounter = 5;
        StartCoroutine("countdownTurn"); // simply ticks down turningCounter every 0.n seconds
      }

      if (turningCounter == 3) setRenderDirection(); // ie. routine for transforming localscale (mirroring the image)

      // show player in profile at end of counter
      profileRenderer.enabled = turningCounter < 1;
      // show player turning towards camera on 4 and away from camera on 1
      turningRenderer.enabled = turningCounter == 4 || turningCounter == 1;
      // show player looking dead center for 2 counts
      centerRenderer.enabled = turningCounter == 2 || turningCounter == 3;

      if (turningCounter < 1)
      {
        isTurning = false;
        defaultAnimator.SetBool("isTurning",false);
      }
  }
select datefromparts(ci2.dt_yr,ci4.dt_mo,ci3.dt_day) dt_from_parts
from (values ('2021_8_12_17_4_blahblahblahblah'),('2021_28_6_42_blahblahblahblah')) string(dt) 
     cross apply (values (charindex('_',string.dt,1))) ci1(loc)
     cross apply (values (charindex('_',ci1.loc+1),left(string.dt,ci1.loc-1))) ci2(loc,dt_yr)
     cross apply (values (charindex('_',ci2.loc+1),substring(string.dt,ci1.loc+1,(ci2.loc-ci1.loc)-1))) ci3(loc,dt_day)
     cross apply (values (substring(string.dt,ci2.loc+1,(ci3.loc-ci2.loc)-1))) ci4(dt_mo);

假设这段代码难看,而且看不完。它可以被提取到一个 SCHEMABOUND 内联表值函数中,你可以使用 CROSS APPLY 来简化查询。

dt_from_parts
2021-12-08
2021-06-28

然后查询可能看起来像这样

drop function if exists dbo.test_fnExtractDate;
go
create function dbo.test_fnExtractDate(
    @input_string            varchar(64))
returns table with schemabinding as return 
select datefromparts(ci2.dt_yr,ci3.dt_day) dt_from_parts
from (values (@input_string)) string(dt) 
     cross apply (values (charindex('_',(ci3.loc-ci2.loc)-1))) ci4(dt_mo);
go
select fex.*
from (values ('2021_8_12_17_4_blahblahblahblah'),('2021_28_6_42_blahblahblahblah')) string(dt) 
    cross apply dbo.test_fnExtractDate(string.dt) fex

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...