SQL CASE意外结果

时间:2014-10-15 18:26:37

标签: sql sql-server-2008

我正在使用SQL 2008并尝试运行查询,我在其中检查多列中的值并在新列中连接结果。从我的研究看起来我需要使用CONCAT来做到这一点,但我似乎无法弄清楚我将把它放在我的查询中。此外,我遇到的第一个问题是我的查询似乎返回了所有内容的不准确结果。

我有一个'Shifts'表,其中包含一个EmplID以及一周中每一天(类型位)和时间的不同列。如下:

ShiftsID    EmplID  M   Tu  W   Th  F   Sa  Su  StartTime   EndTime
2001        1001    0   0   0   0   0   0   1   8:30:00     15:00:00
2002        1001    1   1   1   1   1   0   0   7:00:00     15:00:00

My Personnel表格如下所示:

LegalName   EmployeeID
Doe, John   1001

我的查询如下所示

SELECT Shifts.ShiftsID,
       X.WorkingDays,
       Personnel.EmployeeID,
       Personnel.FullName,
       Shifts.Start,
       Shifts.End
FROM   (SELECT *,
               CASE
                 WHEN Shifts.M = '1' THEN 'M'
                 WHEN Shifts.Tu = '1'THEN 'Tu'
                 WHEN Shifts.W = '1' THEN 'W'
                 WHEN Shifts.Th = '1' THEN 'Th'
                 WHEN Shifts.F = '1' THEN 'F'
                 WHEN Shifts.Sa = '1' THEN 'Sa'
                 WHEN Shifts.Su = '1' THEN 'Su'
                 ELSE NULL
               END AS WorkingDays
        FROM   Shifts
        WHERE  EmplID = '1001') X,
       Personnel
       INNER JOIN Shifts
               ON Personnel.EmployeeID = Shifts.EmplID
WHERE  ( Personnel.EmployeeID = '1001' )
       AND ( X.WorkingDays != '' ) 

此查询的结果是:

ShiftsID    WorkingDays EmployeeID  LegalName   StartTime   EndTime
2001        Su          1001        Doe, John   8:30:00     15:00:00
2002        Su          1001        Doe, John   7:00:00     15:00:00
2001        M           1001        Doe, John   8:30:00     15:00:00
2002        M           1001        Doe, John   7:00:00     15:00:00

我实际需要展示的内容如下:

ShiftsID    WorkingDays EmployeeID  LegalName   StartTime   EndTime
2001        Su          1001        Doe, John   8:30:00     15:00:00
2002        MTuWThF     1001        Doe, John   7:00:00     15:00:00

那么,我当前的查询错误地给了我意想不到的结果呢?我在哪里放置CONCAT以根据需要连接有效的WorkingDays?或者我应该使用除CONCAT之外的其他选项吗?

2 个答案:

答案 0 :(得分:2)

我认为这应该有效SQL Fiddle

SELECT *
FROM   (SELECT Shifts.ShiftsID,
               ISNULL((SELECT 'M' WHERE Shifts.M = '1'), '')
               + ISNULL((SELECT 'Tu' WHERE Shifts.Tu = '1'), '')
               + ISNULL((SELECT 'W' WHERE Shifts.W = '1'), '')
               + ISNULL((SELECT 'Th' WHERE Shifts.Th = '1'), '')
               + ISNULL((SELECT 'F' WHERE Shifts.F = '1'), '')
               + ISNULL((SELECT 'Sa' WHERE Shifts.Sa = '1'), '')
               + ISNULL((SELECT 'Su' WHERE Shifts.Su = '1'), '') AS WorkingDays,
               Personnel.EmployeeID,
               Personnel.LegalName,
               StartTime,
               EndTime
        FROM   Shifts
               INNER JOIN Personnel
                       ON Personnel.EmployeeID = Shifts.EmplID
        WHERE  Personnel.EmployeeID = '1001') T
WHERE  WorkingDays <> '' 

这应该连接几天。使用ISNULL((SELECT ...),'')虽然SQL Server 2008不支持IIF语句。

答案 1 :(得分:2)

这看起来很简单 - 除非我遗漏了什么。我使用CASE表达式创建了一个员工工作日的字符串。

此查询似乎产生了预期的结果。

SELECT *

    -- string representing all working days.
    ,CASE WHEN Shifts.M = '1' THEN 'M' ELSE '' END +
        CASE WHEN Shifts.Tu = '1' THEN 'Tu' ELSE '' END +
        CASE WHEN Shifts.W = '1' THEN 'W' ELSE '' END +
        CASE WHEN Shifts.Th = '1' THEN 'Th' ELSE '' END +
        CASE WHEN Shifts.F = '1' THEN 'F' ELSE '' END +
        CASE WHEN Shifts.Sa = '1' THEN 'Sa' ELSE '' END +
        CASE WHEN Shifts.Su = '1' THEN 'Su' ELSE '' END AS [WorkingDays]

FROM
    #Shifts AS Shifts
    --  INNER JOIN Personnel ON Personnel.EmployeeID=Shifts.EmplID
WHERE EmplID = '1001'
    -- only show shifts that contain one or more day?
    AND (
        Shifts.M='1' OR
        Shifts.Tu='1' OR 
        Shifts.W='1' OR 
        Shifts.Th='1' OR 
        Shifts.F='1' OR 
        Shifts.Sa='1' OR 
        Shifts.Su='1'
    );