【问题标题】:SQL CASE Unexpected ResultsSQL CASE 意外结果
【发布时间】:2014-10-15 18:26:36
【问题描述】:

我正在使用 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

我的 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 之外的其他选项吗?

【问题讨论】:

  • CONCAT 仅适用于 SQL Server 2012。 + 运算符在以前的版本中做类似的事情。看起来您忘记为派生表 X 添加连接条件,所以您获得了交叉连接。
  • 看起来您在 20012002 之间交叉 ShiftID 上的数据并得到混合结果
  • 你不会得到意想不到的结果,重复或更多的加入将导致交叉加入的情况,所以对于给定的数据,第一个 WorkingDays 是 Su 所以它会重复两次然后 M 等等。如何在 sql server 中进行分组,您可以使用 FOR XML PATH

标签: sql sql-server-2008


【解决方案1】:

我认为这应该可以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 语句。

【讨论】:

  • 正是我需要的!非常感谢。
【解决方案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'
    );

【讨论】:

  • 有点吹毛求疵,但CASE 是一个表达式。 SQL 中的语句将是SELECTUPDATE 等。
猜你喜欢
  • 1970-01-01
  • 2015-10-02
  • 2014-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多