简体   繁体   English

SQL 服务器 select 语句的问题

[英]Issue with SQL Server select statement

I need help with a select statement that I'm currently struggling with.我需要 select 语句的帮助,我目前正在努力解决这个问题。 The scenario is this:场景是这样的:

select * from mytable WHERE isActive=1 select * 来自 mytable WHERE isActive=1

  1. and if only id is provided, select everything where the id=@id如果仅提供 id,则 select id=@id 的所有内容
  2. if firstname and lastname is provided, then select everything where firstname=@firstname and lastname=@lastname regardless of the ID如果提供了 firstname 和 lastname,则 select firstname=@firstname 和 lastname=@lastname 的所有内容,无论 ID
  3. if either firstname or lastname is provided, select everything where firstname=@firstname or lastname=@lastname regardless of the ID again如果提供了 firstname 或 lastname,则 select firstname=@firstname 或 lastname=@lastname 的所有内容再次与 ID 无关
  4. if id, firstname and lastname provided, just select where firstname=@firstname and lastname=@lastname regardless of the ID again如果提供了 id、firstname 和 lastname,则只需 select 其中 firstname=@firstname 和 lastname=@lastname 再次与 ID 无关

Here's my query:这是我的查询:

DECLARE @ID INT =25,
@firstname NVARCHAR(100),
@lastname NVARCHAR(100);
SELECT * from mytable
where isActive=1
and ( ID = -1 or ID = @ID) 
or (firstname = @firstname)
or (lastname = @lastname) 
or (firstname = @firstname and lastname = @lastname)

somehow I'm not getting the results expected, for example when I provide both firstname and lastname, it shows everyone with the firstname regardless of their lastname:-(不知何故,我没有得到预期的结果,例如,当我同时提供名字和姓氏时,它会显示每个人的名字,而不管他们的姓氏如何:-(

Please help请帮忙

Not sure if you need a union, especially UNION ALL, but you have two choices.不确定您是否需要工会,尤其是 UNION ALL,但您有两个选择。 First one is pretty, it works with small data sets.第一个很漂亮,它适用于小型数据集。 The second option looks ugly, but gives you almost guaranteed best performance.第二个选项看起来很难看,但几乎可以保证为您提供最佳性能。

SELECT * FROM mytable WHERE isActive=1
    AND (
        (@ID IS NOT NULL AND @firstname IS NULL AND @lastname IS NULL AND @ID = ID) OR
        (@firstname IS NOT NULL AND @lastname IS NOT NULL AND firstname=@firstname and lastname=@lastname) OR
        (@firstname IS NOT NULL AND @lastname IS NULL AND firstname=@firstname) OR
        (@firstname IS NULL AND @lastname IS NOT NULL AND lastname=@lastname)
    )

IF @ID IS NULL AND @firstname IS NULL AND @lastname IS NULL
SELECT * FROM mytable WHERE isActive=1;

IF @ID IS NOT NULL AND @firstname IS NULL AND @lastname IS NULL
SELECT * FROM mytable WHERE isActive=1 AND @ID = ID;

IF @firstname IS NOT NULL AND @lastname IS NOT NULL 
SELECT * FROM mytable WHERE isActive=1 AND firstname=@firstname AND lastname=@lastname;

IF @firstname IS NOT NULL AND @lastname IS NULL 
SELECT * FROM mytable WHERE isActive=1 AND firstname=@firstname;

IF @firstname IS NULL AND @lastname IS NOT NULL 
SELECT * FROM mytable WHERE isActive=1 AND lastname=@lastname;

That is with no difference between #2 & #4, unless you can describe it.除非您可以描述它,否则#2和#4之间没有区别。

Please try the following method.请尝试以下方法。 Though the WHERE clause predicates are not SARGable.虽然WHERE子句谓词不是 SARGable。

SQL SQL

DECLARE @ID INT =25
    , @firstname NVARCHAR(100) = NULL
    , @lastname NVARCHAR(100) = NULL;

SELECT * 
FROM mytable
WHERE isActive = 1
    AND ID = COALESCE(@ID, -1) -- or COALESCE(@ID, ID) depending on the logic
    AND firstname = COALESCE(@firstname, firstname)
    AND lastname = COALESCE(@lastname, lastname);

It is possible to write these as one query, but owing to the way indexes are used, it will probably result in an inefficient table scan.可以将这些写为一个查询,但由于使用索引的方式,它可能会导致低效的表扫描。 Therefore you are best off using UNION ALL to join the separate queries:因此,您最好使用UNION ALL来加入单独的查询:

;WITH cte AS (
    select * from mytable WHERE isActive=1
)
SELECT *
    FROM cte
    WHERE firstname = @firstname AND @lastname IS NULL
UNION ALL
SELECT *
    FROM cte
    WHERE lastname = @lastname AND @firstname IS NULL
UNION ALL
SELECT *
    FROM cte
    WHERE firstname = @firstname AND lastname = @lastname
UNION ALL
SELECT *
    FROM cte
    WHERE ID = @ID
        AND @firstname IS NULL AND AND @lastname IS NULL
OPTION(OPTIMIZE FOR UNKNOWN);

The UNKNOWN bit hints to the compiler that you don't know what may be entered, and it shouldn't keep the parameter values from the first run (parameter sniffing). UNKNOWN位向编译器提示您不知道可能输入的内容,并且不应保留第一次运行的参数值(参数嗅探)。

An alternative hint is OPTION(RECOMPILE) , which means the query will be recompiled on every run.另一种提示是OPTION(RECOMPILE) ,这意味着查询将在每次运行时重新编译。 This has overhead, though.不过,这有开销。

Write it as a series of IF statements:将其写为一系列 IF 语句:

--Test #1
DECLARE @ID INT = 25, @firstname NVARCHAR(100) = 'Florian', @lastname NVARCHAR(100) = 'Voss';

IF (@firstname IS NOT NULL AND @lastname IS NOT NULL)
    SELECT *
    FROM [AdventureWorks2019].[Person].[Person]
    WHERE (firstname = @firstname AND lastname = @lastname)

IF @firstname IS NOT NULL AND @lastname IS NULL
    SELECT *
    FROM [AdventureWorks2019].[Person].[Person]
    WHERE (firstname = @firstname)
GO

--Test #2
DECLARE @ID INT = 25, @firstname NVARCHAR(100) = 'Florian', @lastname NVARCHAR(100) = NULL;

IF (@firstname IS NOT NULL AND @lastname IS NOT NULL)
    SELECT *
    FROM [AdventureWorks2019].[Person].[Person]
    WHERE (firstname = @firstname AND lastname = @lastname)

IF (@firstname IS NOT NULL AND @lastname IS NULL)
    SELECT *
    FROM [AdventureWorks2019].[Person].[Person]
    WHERE (firstname = @firstname)
GO

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM