【问题标题】:SQL Switch/Case in 'where' clause'where' 子句中的 SQL 切换/大小写
【发布时间】:2010-09-17 09:57:56
【问题描述】:

我尝试四处搜索,但找不到任何可以帮助我的东西。

我正在尝试在 SQL 中执行此操作:

declare @locationType varchar(50);
declare @locationID int;

SELECT column1, column2
FROM viewWhatever
WHERE
CASE @locationType
    WHEN 'location' THEN account_location = @locationID
    WHEN 'area' THEN xxx_location_area = @locationID
    WHEN 'division' THEN xxx_location_division = @locationID

我知道我不应该把'= @locationID'放在每一个的末尾,但我无法得到接近正确的语法。 SQL 一直在抱怨我的 '=' 在第一行 WHEN...

我该怎么做?

【问题讨论】:

    标签: sql switch-statement case


    【解决方案1】:
    declare @locationType varchar(50);
    declare @locationID int;
    
    SELECT column1, column2
    FROM viewWhatever
    WHERE
    @locationID = 
      CASE @locationType
          WHEN 'location' THEN account_location
          WHEN 'area' THEN xxx_location_area 
          WHEN 'division' THEN xxx_location_division 
      END
    

    【讨论】:

    • 正如 TomH 在下面对您的回复的评论中指出的那样,您形成的 SQL 不正确。我在 SQLServer 2005 中测试了我的,它运行良好。
    • 为什么需要@?他们是做什么的?
    • @ 表示 t-sql 中的变量,没有 @ ,@locationID 将被解释为列名。
    【解决方案2】:

    没有case语句...

    SELECT column1, column2
    FROM viewWhatever
    WHERE
        (@locationType = 'location' AND account_location = @locationID)
        OR
        (@locationType = 'area' AND xxx_location_area = @locationID)
        OR
        (@locationType = 'division' AND xxx_location_division = @locationID)
    

    【讨论】:

    • 这将给出一个稍微不同的结果,因为条件满足后 Case 语句退出 - 但 OR 语法将评估所有可能性
    • @tember 即使 SQL 是一种过程语言,如果第一个 OR 为真,则表达式的其余部分不会被计算。由于 SQL 是一种声明性语言,您如何知道 DBM 将评估所有 OR?真诚的问题,我不明白。
    • 在 SQL 中,表达式的其余部分确实在 OR 语法中求值。试试这个(它不会让我包含 @ 符号 - 如果你想测试它,你必须更正它): declare var varchar(5) set var = '0' select 2 / var where var 0 或ISNUMERIC(var) = 1。我希望条件退出,因为 var IS 等于 0,但它会继续检查它是否是数字,它是数字,因此该语句返回错误。
    • 这对我的情况有所帮助,因为我对类型的每个值都有不同的比较运算符。
    • 还是DECLARE @locationType NVARCHAR(50) = 'youchoose' IF @locationType = 'location' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (account_location = @locationID) END IF @locationType = 'area' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (xxx_location_area = @locationID) END IF @locationType = 'division' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (xxx_location_division = @locationID) END
    【解决方案3】:

    给你。

    SELECT
       column1, 
       column2
    FROM
       viewWhatever
    WHERE
    CASE 
        WHEN @locationType = 'location' AND account_location = @locationID THEN 1
        WHEN @locationType = 'area' AND xxx_location_area = @locationID THEN 1
        WHEN @locationType = 'division' AND xxx_location_division = @locationID THEN 1
        ELSE 0
    END = 1
    

    【讨论】:

    • 好吧,我会把它写成 SELECT column1, column2 FROM viewWhatever WHERE (@locationType = 'location' AND account_location = @locationID) OR (@locationType = 'area' AND xxx_location_area = @locationID)或(@locationType = 'division' AND xxx_location_division = @locationID)
    • 这是一个很好的例子,最好回答的查询执行计划怎么样(我个人更喜欢这种方法代码清晰干净)
    • 如果你想在第一个子句上使用不同类型的不同 where 子句(如 int 在第一个子句和 nvarchar 在第二个子句),那就太好了。使用 Bob Probst 的解决方案是行不通的。谢谢
    【解决方案4】:

    这样做的问题是,当 SQL 引擎去评估表达式时,它会检查 FROM 部分以提取正确的表,然后检查 WHERE 部分以提供一些基本条件,因此它无法正确评估动态条件要检查的列。

    在检查谓词中的 WHERE 条件时可以使用 WHERE 子句,例如

    WHERE account_location = CASE @locationType
                                  WHEN 'business' THEN 45
                                  WHEN 'area' THEN 52
                             END
    

    因此,在您的特定情况下,您需要将查询放入存储过程或创建三个单独的查询。

    【讨论】:

      【解决方案5】:

      我会说这是一个有缺陷的表结构的指标。也许不同的位置类型应该在不同的表中分开,使您能够进行更丰富的查询并避免周围有多余的列。

      如果您无法更改结构,以下方法可能会起作用:

      SELECT
          *
      FROM
          Test
      WHERE
          Account_Location = (
              CASE LocationType
                WHEN 'location' THEN @locationID
                ELSE Account_Location
              END
          )
          AND
          Account_Location_Area = (
              CASE LocationType
                WHEN 'area' THEN @locationID
                ELSE Account_Location_Area
              END
          )
      

      等等...我们不能即时更改查询的结构,但我们可以通过使谓词等于自己来覆盖它。

      编辑:上述建议当然要好得多,请忽略我的建议。

      【讨论】:

      • 我不认为这是一个有缺陷的表结构。该表是这样设置的,因此它是具有无限数量的父/子关系的自我引用。相信我,这是故意的。我不认为我想将表结构更改为仅使用 switch 语句。它不是那么重要
      【解决方案6】:

      OR 运算符可以在 where 条件下替代大小写

      ALTER PROCEDURE [dbo].[RPT_340bClinicDrugInventorySummary]
          -- Add the parameters for the stored procedure here
           @ClinicId BIGINT = 0,
           @selecttype int,
           @selectedValue varchar (50)
      AS
      BEGIN
      -- SET NOCOUNT ON added to prevent extra result sets from
      -- interfering with SELECT statements.
      SET NOCOUNT ON;
      SELECT
          drugstock_drugname.n_cur_bal,drugname.cdrugname,clinic.cclinicname
      
      FROM drugstock_drugname
      INNER JOIN drugname ON drugstock_drugname.drugnameid_FK = drugname.drugnameid_PK
      INNER JOIN drugstock_drugndc ON drugname.drugnameid_PK = drugstock_drugndc.drugnameid_FK
      INNER JOIN drugndc ON drugstock_drugndc.drugndcid_FK = drugndc.drugid_PK
      LEFT JOIN clinic ON drugstock_drugname.clinicid_FK = clinic.clinicid_PK
      
      WHERE   (@ClinicId = 0 AND 1 = 1)
          OR  (@ClinicId != 0 AND drugstock_drugname.clinicid_FK = @ClinicId)
      
          -- Alternative Case When You can use OR
          AND ((@selecttype = 1 AND 1 = 1)
          OR  (@selecttype = 2 AND drugname.drugnameid_PK = @selectedValue)
          OR  (@selecttype = 3 AND drugndc.drugid_PK = @selectedValue)
          OR  (@selecttype = 4 AND drugname.cdrugclass = 'C2')
          OR  (@selecttype = 5 AND LEFT(drugname.cdrugclass, 1) = 'C'))
      
      ORDER BY clinic.cclinicname, drugname.cdrugname
      END
      

      【讨论】:

        【解决方案7】:

        请试试这个查询。 回复以上帖子:

        select @msgID, account_id
            from viewMailAccountsHeirachy
            where 
            CASE @smartLocationType
                WHEN 'store' THEN account_location
                WHEN 'area' THEN xxx_location_area 
                WHEN 'division' THEN xxx_location_division 
                WHEN 'company' THEN xxx_location_company 
            END  = @smartLocation
        

        【讨论】:

        【解决方案8】:

        试试这个:

        WHERE (
            @smartLocationType IS NULL 
            OR account_location = (
                 CASE
                    WHEN @smartLocationType IS NOT NULL 
                         THEN @smartLocationType
                    ELSE account_location 
                 END
            )
        )
        

        【讨论】:

        • 投了反对票,因为我不明白如何在给定的字符串(即“位置”、“区域”、“分区”)之间进行选择
        【解决方案9】:
        CREATE PROCEDURE [dbo].[Temp_Proc_Select_City]
            @StateId INT
        AS  
                BEGIN       
                    SELECT * FROM tbl_City 
                        WHERE 
                        @StateID = CASE WHEN ISNULL(@StateId,0) = 0 THEN 0 ELSE StateId END ORDER BY CityName
                END
        

        【讨论】:

          【解决方案10】:

          试试这个查询,它非常简单实用:它可以执行了!

          USE tempdb
          GO
          
          IF NOT OBJECT_ID('Tempdb..Contacts') IS NULL
              DROP TABLE Contacts
          
          CREATE TABLE Contacts(ID INT, FirstName VARCHAR(100), LastName VARCHAR(100))
          INSERT INTO Contacts (ID, FirstName, LastName)
          SELECT 1, 'Omid', 'Karami'
          UNION ALL
          SELECT 2, 'Alen', 'Fars'
          UNION ALL
          SELECT 3, 'Sharon', 'b'
          UNION ALL
          SELECT 4, 'Poja', 'Kar'
          UNION ALL
          SELECT 5, 'Ryan', 'Lasr'
          GO
           
          DECLARE @FirstName VARCHAR(100)
          SET @FirstName = 'Omid'
           
          DECLARE @LastName VARCHAR(100)
          SET @LastName = '' 
           
          SELECT FirstName, LastName
          FROM Contacts
          WHERE  
              FirstName = CASE
              WHEN LEN(@FirstName) > 0 THEN  @FirstName 
              ELSE FirstName 
              END
          AND
              LastName = CASE
              WHEN LEN(@LastName) > 0 THEN  @LastName 
              ELSE LastName
              END
          GO
          

          【讨论】:

            【解决方案11】:
            Case Statement in SQL Server Example
            
            Syntax
            
            CASE [ expression ]
            
               WHEN condition_1 THEN result_1
               WHEN condition_2 THEN result_2
               ...
               WHEN condition_n THEN result_n
            
               ELSE result
            
            END
            
            Example
            
            SELECT contact_id,
            CASE website_id
              WHEN 1 THEN 'TechOnTheNet.com'
              WHEN 2 THEN 'CheckYourMath.com'
              ELSE 'BigActivities.com'
            END
            FROM contacts;
            
            OR
            
            SELECT contact_id,
            CASE
              WHEN website_id = 1 THEN 'TechOnTheNet.com'
              WHEN website_id = 2 THEN 'CheckYourMath.com'
              ELSE 'BigActivities.com'
            END
            FROM contacts;
            

            【讨论】:

            • 投反对票,因为此答案与问题无关。问题是如何在 WHERE 子句上使用 CASE,而不是如何在 SELECTed 列上使用 CASE。
            【解决方案12】:

            这对我有用。

            CREATE TABLE PER_CAL ( CAL_YEAR INT, CAL_PER INT ) INSERT INTO PER_CAL( CAL_YEAR, CAL_PER ) VALUES ( 20,1 ), ( 20,2 ), ( 20,3 ), ( 20,4 ), ( 20,5 ), ( 20,6 ), ( 20,7 ), ( 20,8 ), ( 20,9 ), ( 20,10 ), ( 20,11 ), ( 20,12 ), ( 99,1 ), ( 99,2 ), ( 99,3 ), ( 99,4 ), ( 99,5 ), ( 99,6 ), ( 99,7 ), ( 99,8 ), ( 99,9 ), ( 99,10 ), ( 99,11 ), ( 99,12 )

            4位世纪由规则确定,如果年份大于等于50,则世纪为1900,否则为2000。

            给定两个标记开始和结束时间段的 6 位数时间段,例如四分之一,返回该范围内的行。

            -- 1st quarter of 2020 SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 202001 AND 202003 -- 4th quarter of 1999 SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 199910 AND 199912

            【讨论】:

              【解决方案13】:

              试试这个查询。很容易理解:

              CREATE TABLE PersonsDetail(FirstName nvarchar(20), LastName nvarchar(20), GenderID int);
              GO
              
              INSERT INTO PersonsDetail VALUES(N'Gourav', N'Bhatia', 2),
                            (N'Ramesh', N'Kumar', 1),
                            (N'Ram', N'Lal', 2),
                            (N'Sunil', N'Kumar', 3),
                            (N'Sunny', N'Sehgal', 1),
                            (N'Malkeet', N'Shaoul', 3),
                            (N'Jassy', N'Sohal', 2);
              GO
              
              SELECT FirstName, LastName, Gender =
                  CASE GenderID
                  WHEN 1 THEN 'Male'
                  WHEN 2 THEN 'Female'
                  ELSE 'Unknown'
                  END
              FROM PersonsDetail
              

              【讨论】:

              猜你喜欢
              • 2013-08-01
              • 2020-12-06
              • 2017-01-23
              • 2016-11-26
              • 2011-10-16
              • 2016-09-03
              • 2017-06-21
              • 2011-10-29
              • 1970-01-01
              相关资源
              最近更新 更多