使用基于另一列的值构建的字符串更新数据库列

时间:2016-11-11 15:55:35

标签: sql tsql sql-server-2008-r2

我有一个名为Days的列表。 Days列存储以逗号分隔的字符串,表示星期几。例如,值1,2代表Sunday, Monday。我想将它转换为JSON并将其存储在同一个表中名为Frequency的列中,而不是将此信息存储为逗号分隔的字符串。例如,应更新Days值为1,2的记录,以便将以下内容存储在Frequency列中:

'{"weekly":"interval":1,"Sunday":true,"Monday":true,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}' 

我找到了一种使用case语句的方法,假设Days列中只有一个数字,如下所示:

UPDATE SCH_ITM 
SET
    FREQUENCY = 
        CASE 
        WHEN SCH_ITM.DAYS = 1 THEN '{"weekly":{"interval":1,"Sunday":true,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}' 
        WHEN SCH_ITM.DAYS = 2 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":true,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}' 
        WHEN SCH_ITM.DAYS = 3 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":true,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}' 
        WHEN SCH_ITM.DAYS = 4 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":true,"Thursday":false,"Friday":false,"Saturday":false}}' 
        WHEN SCH_ITM.DAYS = 5 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":true,"Friday":false,"Saturday":false}}' 
        WHEN SCH_ITM.DAYS = 6 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":true,"Saturday":false}}' 
        WHEN SCH_ITM.DAYS = 7 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":true}}' 
        END
WHERE SCH_TYPE = 'W';

然而,我似乎无法找到一种有效的方法来处理将1,5之类的值转换为正确的JSON表示。显然我可以写出所有可能的排列,但肯定是更好的方法吗?

2 个答案:

答案 0 :(得分:1)

借助解析功能和交叉应用

;with cteDays As (Select ID,Name From (Values(1,'Sunday'),(2,'Monday'),(3,'Tuesday'),(4,'Wednesday'),(5,'Thursday'),(6,'Friday'),(7,'Saturday')) D(ID,Name))

Update YourTable Set Frequency =  '{"weekly":"interval":1,'+String+'}}'
 From  YourTable A
 Cross Apply (
              Select String = Stuff((Select ','+String 
              From (
                    Select String='"'+Name+'":'+case when RetVal is null then 'false' else 'true' end
                    From   [dbo].[udf-Str-Parse](A.Days,',') A
                    Right Join cteDays B on RetVal=ID) N
              For XML Path ('')),1,1,'') 
             ) B

Select * from YourTable

更新表

Days    Frequency
1,2     {"weekly":"interval":1,"Sunday":true,"Monday":true,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}
1,2,3   {"weekly":"interval":1,"Sunday":true,"Monday":true,"Tuesday":true,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}

UDF(如果需要)

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From (Select x = Cast('<x>'+ Replace(@String,@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')

答案 1 :(得分:1)

好的,这将为您提供您所要求的内容

create table test (days varchar(20), frequency varchar(500))

insert into test(days) values('1'),('2'),('3'),('4'),('5'),('6'),('7'),('1,5')

update test set frequency = '{"weekly":{"interval":1,'
    + '"Sunday": ' + case when days like '%1%' then 'true' else 'false' end + ','
    + '"Monday": ' + case when days like '%2%' then 'true' else 'false' end + ','
    + '"Tuesday": ' + case when days like '%3%' then 'true' else 'false' end + ','
    + '"Wednesday": ' + case when days like '%4%' then 'true' else 'false' end + ','
    + '"Thursday": ' + case when days like '%5%' then 'true' else 'false' end + ','
    + '"Friday": ' + case when days like '%6%' then 'true' else 'false' end + ','
    + '"Saturday": ' + case when days like '%7%' then 'true' else 'false' end + '}}'

select * from test

当然,例如Days ='1234'将产生与'1,2,3,4'相同的效果 - 就像'Bl4arg3le12'一样。如果Days是一个字符串,你可以把'8'放在没有意义的地方吗?

听起来你需要一两个额外的桌子,这是真的:

如果“MyTable”是带有Days列的表,请添加带有星期几的Days表,然后使用MyTableDays表将MyTable条目链接到天 - 对于1,5示例,将有两行MyTableDays