SQL Server:CASE 语句中的 OR 语句

Posted

技术标签:

【中文标题】SQL Server:CASE 语句中的 OR 语句【英文标题】:SQL Server : OR statement within CASE statement 【发布时间】:2018-05-22 21:43:15 【问题描述】:

我有一个存储过程,它根据用户发送的内容查询一些员工记录。

在 UI 上,用户将输入多个数据点,例如电子邮件地址、用户 ID 或员工姓名。此存储过程检查它们提供的数据类型,然后在数据库中的该字段中搜索记录。

存储过程的输入:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <data>
      <dataPoints>
         <dataPoint>
            <order>0</order>
            <value>Jim Bob</value>
         </dataPoint>
         <dataPoint>
            <order>1</order>
            <value>Sally Jones</value>
         </dataPoint>
      </dataPoints>
   </data>
</root>

查询:

    @dataType VARCHAR (20), @data XML
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN

    -- Create a temp table 
    DECLARE @dataSet TABLE (data VARCHAR(100), [order] INT);

    INSERT INTO @dataSet( data , [order] )
        SELECT  
            ParamValues.x1.value('value[1]', 'VARCHAR(100)') ,
            ParamValues.x1.value('order[1]', 'INT') 
        FROM 
            @data.nodes('/root/data/dataPoints/dataPoint') AS ParamValues(x1)

    -- Search Employees
    SELECT 
        ec.FirstName, ec.PreferredName, ec.LastName,
        ec.NTID, ec.QID,
        ec.DepartmentName, ec.SegmentName,
        ec.CenterName, ec.RoleName, ec.MarketName,
        ec.IncentivePlanName,
        ec.CostCenterID,
        ec.SupFirstName, ec.SupPreferredName, ec.SupLastName,
        ec.SiloName,
        ec.AreaName,
        ec.PersonnelID,
        d.[order]
    FROM
        Resources.emp.EmployeeComplete AS ec
    INNER JOIN
        @dataset AS d ON d.data = CASE 
                                     WHEN @dataType = 'NTID' THEN ec.ntid 
                                     WHEN @dataType = 'QID' THEN ec.QID 
                                     WHEN @dataType = 'Emp ID' THEN ec.EmpID 
                                     WHEN @dataType = 'Email Address' THEN ec.Email 
                                     WHEN @dataType = 'Personnel ID' OR @dataType = 'Sap ID' THEN ec.PersonnelID 
                                     --WHEN @dataType = 'Name' THEN (
                                     -- (ec.FirstName + ' ' + ec.LastName) 
                                     --     OR (ec.PreferredName + ' ' + ec.LastName)
                                     --     OR (ec.LastName + ', ' + ec.FirstName)
                                     --     OR (ec.LastName + ', ' + ec.PreferredName
                                     -- )
                        END
    FOR XML PATH ('employees'), ELEMENTS, TYPE, ROOT ('root');

简而言之,我将正在搜索的多个数据点放入 XML 字符串中以传递给存储过程。一旦他们到达,我将它们放入一个临时表中,以便我可以将其与我的主要员工记录一起加入。

问题/疑问:

您会看到我的示例中有一些注释掉的代码,这就是我的问题所在。我的数据库中有三个名称字段。 First NamePreferred NameLast Name

我基本上需要测试用户提供的内容,并根据他们输入的组合找到员工。用户在 UI 中选择的只是他们提供了一个名称,而不是它的格式。

因此,我需要检查是否可以找到几种不同格式的记录。

这种情况下的问题是我无法在CASE 语句中使用OR 条件加入我的数据集。

如果是@dataType = 'Name',我需要能够将我的临时表加入到几种不同的组合可能性中。

我们让他们意识到的一件事是他们不能混搭。这意味着他们无法通过LastName FirstName 搜索进行FirstName LastName

我无法解释这一点,所以如果我需要以某种方式澄清,请告诉我。

【问题讨论】:

您是否考虑过使用动态 SQL 来构建您的查询?这样,您最终会得到一个更简单的 SQL 语句,其中包含每组参数所需的关系。 d.data 每行只能设置一个值。这不是比较情况,所以OR 不适合SELECT。您正在SELECT记录。您想为每种名称格式返回多行吗?您想在一行中将这些多个结果作为分隔记录返回吗? @Shawn - 返回的每条记录将是一个或多个员工记录,具体取决于它找到的内容。如果使用Name 并且我搜索Tom JonesSam Smith,如果它找到任何具有这些名称的员工,它将返回它们。 @DeanOC - 如果归根结底,我可能不得不这样做。希望只有某种我没有想到的结构来处理按名称搜索的最后一种可能性。 当它返回多个名称时,您希望这些名称如何显示?您想要重复其他数据的行,还是想要在主记录的一行中返回一个分隔列表? 【参考方案1】:

推入CASE 中的方程式。如果它们为真,让THEN 返回 1。检查 CASE 是否返回 1。当且仅当它返回时,您才找到匹配项。在WHEN 的条件下,您可以使用布尔运算符。所以你可以在那里建立你的OR(或使用IN,如下所示)。

...
CASE 
WHEN @dataType = 'NTID' AND d.data = ec.ntid THEN 1
WHEN @dataType = 'QID' AND d.data = ec.QID THEN 1
...
WHEN (@dataType = 'Personnel ID' OR @dataType = 'Sap ID') AND d.data = ec.PersonnelID THEN 1
WHEN @dataType = 'Name' AND (d.data IN ('' + ec.FirstName + ' ' + ec.LastName, 
                                        '' + ec.PreferredName + ' ' + ec.LastName,
                                        '' + ec.LastName + ', ' + ec.FirstName,
                                        '' + ec.LastName + ', ' + ec.PreferredName) THEN 1
END = 1
...

【讨论】:

这仍然在我的join 中(我现在拥有它的同一个地方)还是我需要移动它? @SBB:我可以替换旧的CASE,所以留在原地。 试一试,但收到 SQL 错误。 Conversion failed when converting the varchar value 'Billy Bob' to data type int. @SBB:嗯,我猜这只能是+。我试图强制字符串上下文首先添加空字符串(参见编辑)。如果这没有帮助,请尝试 convert()cast()。或者看看这是从哪里来的。 (我假设来自您的一张表的CASE 中的列都不是inetger?) 我认为您需要在每个 IN 条件周围转义单引号。 ''' + ec.FirstName + ' ' + ec.LastName + ''' 也可能是 coalesce()isNull() 来解释 NULLs。【参考方案2】:

将 OR 放入您的联接中怎么样?

FROM    @dataset AS d
        INNER JOIN Resources.emp.EmployeeComplete AS ec
        ON (@dataType = 'NTID' AND ec.ntid = d.data)
            OR (@dataType = 'QID' AND ec.QID = d.data)
            OR (@dataType = 'Emp ID' AND ec.EmpID = d.data)
            OR (@dataType = 'Email Address' AND ec.Email = d.data)
            OR ((@dataType = 'Personnel ID' OR @dataType = 'Sap ID') AND ec.PersonnelID = d.data)
            OR (@dataType = 'Name' AND (ec.FirstName + ' ' + ec.LastName) = d.data)
            OR (@dataType = 'Name' AND (ec.PreferredName + ' ' + ec.LastName) = d.data)
            OR (@dataType = 'Name' AND (ec.LastName + ', ' + ec.FirstName) = d.data)
            OR (@dataType = 'Name' AND (ec.LastName + ', ' + ec.PreferredName) = d.data)

我不确定 SQL 是否足够聪明,可以在这些字段上使用正确的索引(如果有的话),可能尤其是在组合列时。您将为那些组合名称或可以索引的计算列创建索引视图。最好将它们分散到 if/thens 中的单独查询中,以便 SQL 可以根据您要加入的字段优化每个查询并只执行一个查询。

【讨论】:

以上是关于SQL Server:CASE 语句中的 OR 语句的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:CASE 语句中的 OR 语句

where 子句中的 case 语句 - SQL Server

我想使用 CASE 语句来更新 sql server 2005 中的一些记录

SQL Server 2008 - SELECT 子句中的 Case / If 语句 [重复]

sql server 2008 r2:当前会计年度 where 子句中的 case 语句

如何在sql server中使用if语句和case