如何替换和组合 T-SQL 中多列的值

How to replace and combine the values from multiple columns in T-SQL

我在 SQL Server 2016 中有一个 table,用于安排工作日的会议。它将一周中每一天的日期存储在一列中(下面的示例)。我想查询此 table 并以更 user-friendly 的格式在单个列中获取结果。

当前数据存储在 table 中,如下所示:

SCHEDULE TABLE:
MEETING_TITLE | MONDAY | TUESDAY | WEDNESDAY | THURSDAY | FRIDAY
FOO           | NULL   | Y       | NULL      | Y        | NULL  

我的愿望是在结果中合并这些工作日列,并将它们转换为相应日期的缩写。

想要的结果:

SCHEDULE TABLE:
MEETING_TITLE | MEETING_DAYS
FOO           | T/THU

我研究了 case 语句,if/else 并尝试使用声明变量来保存值,但到目前为止没有任何效果。为了展示我解决问题的尝试,我特地尝试声明一个变量来保存格式化的日期。之后,我尝试每天在列中查找 'Y' 时执行 if/else。如果找到了,我希望做一些 += 的事情来根据需要组合这些值。我尝试的一切都导致错误,查询不会 运行.

感谢您对此提供的任何帮助。

(上面的例子当然是简化了,这个table远比上面复杂)

注意:这是 Oracle 语法而不是 sql-server。无论如何将它留在这里供其他可能喜欢它作为 oracle 答案的人使用。

select meeting_title
    , CONCAT( decode( monday, 'Y', 'M' ),' ',
      decode( tuesday, 'Y', 'T' ),' ',
      decode( wednesday, 'Y', 'W' ),' ',
      decode( thursday, 'Y', 'Th' ),' ',
      decode( friday, 'Y', 'F' ) )
from my_schedule
--You can use CASE Statements to concat and then
--a combination of STUFF and REVERSE to remove the trailing / off [MEETING_DAYS]
SELECT [MEETING_TITLE], reverse(stuff(reverse(
CASE WHEN [Monday] IS NULL THEN '' ELSE 'Mon/' END + 
CASE WHEN [Tuesday] IS NULL THEN '' ELSE 'T/' END + 
CASE WHEN [Wednesday] IS NULL THEN '' ELSE 'Wed/' END + 
CASE WHEN [Thursday] IS NULL THEN '' ELSE 'THU/' END + 
CASE WHEN [Friday] IS NULL THEN '' ELSE 'Fri/' END), 1, 1, '')) AS [MEETING_DAYS]
FROM [dbo].[Schedule]

如果您使用的是 SQL 2017 或更高版本,一个简单的实现方法是

select meeting_title,
    Concat_Ws('/',
        Iif(monday is null,null,'Mon'),
        Iif(tuesday is null,null,'tue'),
        Iif(wednesday is null,null,'wed'),
        Iif(thursday is null,null,'thu'),
        Iif(friday is null,null,'fri')
    ) as meeting_days
from schedule

此版本仅适用于 SQL Server 2017 或更高版本(或者如果您使用自定义字符串聚合函数)。

另一个可能是cross apply:

select s.*, v.*
from schedule s cross apply
     (select string_agg(name, '/') within group (order by ord) as meeting_days
      from (values ('M', Monday, 1),
                   ('T', Tuesday, 2),
                   ('W', Wednesday, 3),
                   ('Thu', Thursday, 4),
                   ('F', Friday, 5)
           ) v(name, val, ord)
      where val = 'Y'
     ) v;

请尝试以下解决方案。

要点:

  • 我们正在将感兴趣的列标记为 XML。
  • FOR XML ... 自动过滤掉具有 NULL 值的列。
  • 开始使用 3 个字符来缩写一周中的每一天。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (
    ID INT IDENTITY PRIMARY KEY, 
    meeting VARCHAR(100),
    MONDAY CHAR(1),
    TUESDAY CHAR(1),
    WEDNESDAY CHAR(1),
    THURSDAY CHAR(1),
    FRIDAY CHAR(1)
);
INSERT INTO @tbl (meeting,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) VALUES
('FOO', NULL,'Y',NULL,'Y',NULL),
('New Meeting', 'Y','Y',NULL,'Y',NULL);
-- DDL and sample data population, end

SELECT ID, meeting
    , REPLACE(c.query('
        for $x in /root/*
        return substring(local-name($x),1,3)
    ').value('.', 'VARCHAR(100)'), SPACE(1),'/') AS MEETING_DAYS
FROM @tbl
CROSS APPLY (SELECT MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
    FOR XML PATH(''), TYPE, ROOT('root')) AS t(c);

输出

+----+-------------+--------------+
| ID |   meeting   | MEETING_DAYS |
+----+-------------+--------------+
|  1 | FOO         | TUE/THU      |
|  2 | New Meeting | MON/TUE/THU  |
+----+-------------+--------------+

带有示例数据:

Declare @testData table (
        meeting_title varchar(20)
      , Monday        char(1)
      , Tuesday       char(1)
      , Wednesday     char(1)
      , Thursday      char(1)
      , Friday        char(1)
        );



 Insert Into @testData (meeting_title, Monday, Tuesday, Wednesday, Thursday, Friday)
 Values ('FEE', Null, 'Y', Null, 'Y', Null)
      , ('FIE', 'Y', Null, 'Y', 'Y', Null)
      , ('FOE', 'Y', 'Y', Null, Null, 'Y');

 Select *
      , meeting_days = stuff(concat('/' + iif(td.Monday    = 'Y', 'Mon', Null)
                                  , '/' + iif(td.Tuesday   = 'Y', 'Tue', Null)
                                  , '/' + iif(td.Wednesday = 'Y', 'Wed', Null)
                                  , '/' + iif(td.Thursday  = 'Y', 'Thu', Null)
                                  , '/' + iif(td.Friday    = 'Y', 'Fri', Null)), 1, 1, '')
                                  
   From @testData td;