如何操作字符串 a T-SQL?

How can I manipulate a string a T-SQL?

business_id open_day open_time close_day close_time
1 FRIDAY 08:00 FRIDAY 12:00
1 FRIDAY 13:00 FRIDAY 17:00
1 MONDAY 08:00 MONDAY 17:00
2 SATURDAY 08:00 SATURDAY 16:00
2 SUNDAY 08:00 SUNDAY 16:00
3 MONDAY 08:00 MONDAY 16:00

我的任务是为企业创建和设置营业时间格式,我需要将这些时间按天分组在一个字符串中。然而,它正在重复这一天。如果某个值在一个字符串中出现两次,是否可以搜索该值?我已经走到这一步了:

create table open_times (business_id int, open_day varchar(10), open_time varchar(10), close_day varchar(10), close_time varchar(10) )
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (1, 'FRIDAY', '08:00', 'FRIDAY', '12:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (1, 'FRIDAY', '13:00', 'FRIDAY', '17:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (1, 'MONDAY', '08:00', 'MONDAY', '17:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (2, 'SATURDAY', '08:00', 'SATURDAY', '16:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (2, 'SUNDAY', '08:00', 'SUNDAY', '16:00')
insert into open_times (business_id, open_day, open_time, close_day, close_time) values (3, 'MONDAY', '08:00', 'MONDAY', '16:00')

drop table open_times

感谢您的帮助。

    select 
    business_id
    ,left(name_values, LEN(name_values)-1) as opening_hours
from 
    (
    select 
            results.business_id
            ,STUFF((
                    select
                     ( case when open_day = 'FRIDAY' then 'Fr' when open_day = 'MONDAY' then 'Mo' when open_day = 'TUESDAY' then 'Tu' when open_day = 'WEDNESDAY' then 'We' When open_day = 'THURSDAY' then 'Th' when open_day = 'SATURDAY' then 'Sa' else 'Su' end )
                        + ' ' + open_time + '-' + close_time + '; '
                    from open_times
                    where business_id = results.business_id 
                    for xml path(''),type).value('(./text())[1]','VARCHAR(MAX)'),1,0, '')  as name_values
            from open_times results
            group by business_id
    )  innerquery




Current Output for Business 1: 'Fr 08:00-12:00; Fr 13:00-17:00; Mo 08:00-17:00'   
Desired Output For Business 1: 'Fr 08:00-12:00, 13:00-17:00; Mo 08:00-17:00'

你可以在这里使用STRING_AGG。你只需要做两级分组,每天一次,然后对整个 business_id

SELECT
  ot.business_id,
  Times = STRING_AGG(CONCAT(
       UPPER(LEFT(ot.open_day, 1)),
       LOWER(SUBSTRING(ot.open_day, 2, 1)),
       ' ',
       ot.Times)
     , '; ')
FROM (
    SELECT
      ot.business_id,
      ot.open_day,
      Times = STRING_AGG(CONCAT(
        ot.open_time,
        '-',
        ot.close_time),
      ', ')
    FROM open_times ot
    GROUP BY ot.business_id, ot.open_day
) ot
GROUP BY ot.business_id;

db<>fiddle

对于旧版本,请使用 FOR XML PATH 聚合技巧。假设每天不超过 2 个打开间隔

with t as (
  select business_id, left(open_day,2) +  ' ' + min(open_time + '-' + close_time) +
      case when min(open_time) = max(open_time) then '' 
          else ', ' + max(open_time + '-' + close_time) end ots
  from open_times
  group by business_id, open_day
)
select business_id, stuff( 
     (select '; ' + ots
      from t t2
      where t2.business_id = t1.business_id
      order by left(ots,2)
      for xml path(''))
     , 1, 2, '') opening_hours
from t t1
group by business_id

您可以通过将 window 函数合并到您的逻辑中来使用一级聚合来执行此操作:

select ot.business_id,
       stuff((select (case when seqnum = 1 then '; ' else ', ' end) +
                     (case when seqnum = 1 and ot2.open_day = 'FRIDAY' then 'Fr '
                           when seqnum = 1 and ot2.open_day = 'MONDAY' then 'Mo '
                           when seqnum = 1 and ot2.open_day = 'TUESDAY' then 'Tu '
                           when seqnum = 1 and ot2.open_day = 'WEDNESDAY' then 'We '
                           when seqnum = 1 and ot2.open_day = 'THURSDAY' then 'Th '
                           when seqnum = 1 and ot2.open_day = 'SATURDAY' then 'Sa '
                           when seqnum = 1 then 'Su '
                           else ''
                       end ) +
                    ot2.open_time + '-' + ot2.close_time 
              from (select ot2.*,
                           row_number() over (partition by ot2.open_day order by ot2.open_time) as seqnum
                    from open_times ot2
                    where ot2.business_id = ot.business_id 
                   ) ot2
              order by ot2.open_day, ot2.open_time
              for xml path(''),type
             ).value('(./text())[1]', 'VARCHAR(MAX)'), 1, 2, ''
            )  as name_values
from open_times ot
group by ot.business_id;

Here 是一个 db<>fiddle.

您的查询版本实际上不正确,因为您在 XML 子查询中没有 order by。结果可以是任意顺序。

此外,您不仅要删除重名,还想将分隔符从 ; 更改为 ,

上述查询的思路是枚举每天的时间。分隔符第一次是;,后面的分隔符是,。该缩写仅用于第一个。我还为所有列引用添加了限定条件,这是强烈推荐的做法。

请注意,您可以将 case 逻辑简化为:

left(ot2.open_day, 1) + lower(substring(ot2.open_day, 2, 1))