为什么有人在SQL子句中使用WHERE 1 = 1 AND <conditions>?


256

为什么有人WHERE 1=1 AND <conditions>在SQL子句中使用(通过连接字符串获得的SQL,要么是视图定义)

我在某个地方看到过,它将被用来防止SQL注入,但是看起来很奇怪。

如果进行注射WHERE 1 = 1 AND injected OR 1=1,结果将与相同injected OR 1=1

稍后编辑:视图定义中的用法如何?


谢谢您的回答。

仍然,我不明白为什么有人会使用这种构造来定义视图,或者在存储过程中使用它。

以这个为例:

CREATE VIEW vTest AS
SELECT FROM Table WHERE 1=1 AND table.Field=Value

3
“为什么有人会用这种构造来定义视图”可能是出于习惯。它在静态查询中没有提供任何功能优势。
ADTC 2014年

Answers:


346

如果条件列表在编译时未知,而是在运行时生成,则不必担心您是否拥有一个或多个条件。您可以生成它们,就像:

and <condition>

并将它们连接在一起。随着1=1在开始时,最初and有一些与之交往。

我从未见过将它用于任何形式的注入保护,因为您说这似乎没有太大帮助。我已经将其用作实现的便利。SQL查询引擎最终将忽略1=1它,因此它不会对性能产生影响。


34
有时不是要懒惰,而是要拥有更简洁的代码。
爱德华多·莫尔蒂尼

39
处理尾随AND或COMMA并不算脏……在您的SQL上全都为1 = 1,这是没有比这更干净的了。

21
DBA?他们是干什么的?:)
Eduardo Molteni,

38
认为自己知道如何有效使用数据库的程序员后,DBA会在那里清理。
阿德里安·普龙克

23
“懒惰”我喜欢认为它很聪明,而不是懒惰。您正在避免重复的代码和不必要的条件检查。在无法添加where 1=1(Oracle)或where true(Postgres)的情况下,我将必须检查每个条件是否是第一个条件。这样做是没有意义的,它只会添加更多样板代码。
ADTC 2014年

113

只需在Greg的答案中添加示例代码即可:

dim sqlstmt as new StringBuilder
sqlstmt.add("SELECT * FROM Products")
sqlstmt.add(" WHERE 1=1") 

''// From now on you don't have to worry if you must 
''// append AND or WHERE because you know the WHERE is there
If ProductCategoryID <> 0 then
  sqlstmt.AppendFormat(" AND ProductCategoryID = {0}", trim(ProductCategoryID))
end if
If MinimunPrice > 0 then
  sqlstmt.AppendFormat(" AND Price >= {0}", trim(MinimunPrice))
end if

6
有点古怪,但似乎是一种有效的用法。
迈克,

5
这应该是公认的答案。实际上,这种做法只是绕开而不必确定您有多少条件。
aglassman 2013年

38

当条件数量可变时,我已经看到了它的使用。

您可以使用“ AND”字符串连接条件。然后,不计算传递的条件数,而是在库存SQL语句的末尾放置一个“ WHERE 1 = 1”,并引发连接的条件。

基本上,它省去了对条件进行测试,然后在条件之前添加“ WHERE”字符串的麻烦。


28

似乎总是一种懒惰的方式,可以始终知道您的WHERE子句已定义,并允许您继续添加条件而不必检查它是否是第一个。


12
“懒惰”我喜欢认为它很聪明,而不是懒惰。您正在避免重复的代码和不必要的条件检查。在无法添加where 1=1(Oracle)或where true(Postgres)的情况下,我将必须检查每个条件是否是第一个条件。这样做是没有意义的,它只会添加更多样板代码。
ADTC 2014年

2
@ADTC编写代码通常(如果不是主要的话)是关于处理不同条件的。这只是需要处理的另一个条件,我个人认为这很容易污染生成的SQL。如果您设计代码以将“ Where 1 = 1”添加到一个位置,则可以(无需额外的努力)即可处理代码中该一个位置的零个条件与许多条件之间的差。但我的猜测是,“ 1 = 1”的拥护者们在整个代码库中都撒上了它,这使我得出结论:懒惰滋生了懒惰。
杰森S

@JasonS懒惰是发明之父。
ADTC '16

@ADTC我很懒,因为我不喜欢在数百个地方更新代码,因此本发明将其放在一个地方。对我而言WHERE 1=1,繁琐的工作是在多个位置维护相同的代码,并在所有生成的SQL中读取它。我比你想的要懒!
杰森S

19

间接相关:当使用1 = 2时:

CREATE TABLE New_table_name 
as 
select * 
FROM Old_table_name 
WHERE 1 = 2;

这将创建一个具有与旧表相同架构的新表。(如果要加载一些数据进行比较,非常方便)


3
忘记添加,尽管它将创建一个具有与旧表相同数据的新表,但是新表将没有其他约束,例如旧表中的外键
milso,2013年

16

生成的sql代码中通常使用1 = 1表达式。此表达式可以简化sql生成代码,从而减少条件语句的数量。


11

实际上,我已经在BIRT报告中看到过这种情况。传递给BIRT运行时的查询具有以下形式:

select a,b,c from t where a = ?

和“?” 在运行时由从下拉框中选择的实际参数值替换。下拉菜单中的选项如下:

select distinct a from t
union all
select '*' from sysibm.sysdummy1

这样您将获得所有可能的值加上“ *”。如果用户*从下拉框中选择“ ”(意味着应选择a的所有值),则必须在运行查询之前(通过Javascript)修改查询。

自“?” 是一个位置参数,必须保留在那里以便其他工作,Javascript将该查询修改为:

select a,b,c from t where ((a = ?) or (1==1))

这基本上消除了where子句的影响,同时仍然保留了位置参数。

在动态创建SQL查询时,我还看到了惰性编码器使用的AND格。

假设您必须动态创建一个以开头select * from t并检查的查询:

  • 名字叫鲍勃;和
  • 薪水> $ 20,000

有些人会在第一个添加WHERE,然后在后面添加AND,因此:

select * from t where name = 'Bob' and salary > 20000

懒惰的程序员(不一定是特性)不会在添加的条件之间进行区分,他们会从添加条件开始,select * from t where 1=1然后在其后添加AND子句。

select * from t where 1=1 and name = 'Bob' and salary > 20000

1
“懒惰”我喜欢认为它很聪明,而不是懒惰。您正在避免重复的代码和不必要的条件检查。在无法添加where 1=1(Oracle)或where true(Postgres)的情况下,我将必须检查每个条件是否是第一个条件。这样做是没有意义的,它只会添加更多样板代码。
ADTC 2014年

1
@ADTC,我的意思并不是说懒惰。实际上,懒惰是编程的一个特征:-)我会澄清。
paxdiablo 2014年

懒惰是万恶之源
伊万津尼奥(Ivanzinho)

11

在测试或仔细检查数据库中的内容时,我发现此模式很有用,因此我可以非常迅速地注释其他情况:

CREATE VIEW vTest AS
SELECT FROM Table WHERE 1=1 
AND Table.Field=Value
AND Table.IsValid=true

变成:

CREATE VIEW vTest AS
SELECT FROM Table WHERE 1=1 
--AND Table.Field=Value
--AND Table.IsValid=true

10

其中1 = 0,这是为了检查表是否存在。不知道为什么使用1 = 1。


1
可见,此操作用于从数据库返回空结果集,以用作新记录的持有者。
Gary Kindel

6

虽然我看到1 = 1对于生成的SQL很有用,但是我在PHP中使用的一种技术是创建一个子句数组,然后执行

implode (" AND ", $clauses);

从而避免了前导或尾随AND的问题。显然,这仅在您知道至少要有一个子句的情况下才有用!


1
那就是1 = 1出现的地方。它为您提供了“至少一个子句”,因此您不必担心只是拍打“ AND abc”
卡尔

我喜欢这个主意!看到这里更完整的例子stackoverflow.com/questions/35326160/…–
drooh

5

这是一个密切相关的示例:使用SQL MERGE语句使用源表中的所有值更新表中列出的目标,其中没有可连接的公共属性,例如

MERGE INTO Circles
   USING 
      (
        SELECT pi
         FROM Constants
      ) AS SourceTable
   ON 1 = 1
WHEN MATCHED THEN 
  UPDATE
     SET circumference = 2 * SourceTable.pi * radius;

5

为什么有人使用WHERE 1 = 1 AND <proper conditions>

我已经看到过本地化框架所做的事情(blush),因为这允许将懒惰的解析实践同时应用于WHEREANDSql关键字。

例如(这里我以C#为例),请考虑在Sql查询中对以下谓词进行条件解析string builder

var sqlQuery = "SELECT * FROM FOOS WHERE 1 = 1"
if (shouldFilterForBars)
{
    sqlQuery = sqlQuery + " AND Bars > 3";
}
if (shouldFilterForBaz)
{
    sqlQuery = sqlQuery + " AND Baz < 12";
}

的“好处” WHERE 1 = 1意味着不需要特殊代码:

  • 对于AND-无论是零,都应使用一个或两个谓词(Bars和Baz's),这将确定是否AND需要第一个谓词。由于我们已经有了至少一个谓词1 = 1,所以它AND总是可以的。
  • 对于完全没有谓词的情况-如果存在零个谓词,则WHERE必须丢弃谓词。但同样,我们可以偷懒,因为我们再次保证了至少一个谓词。

这显然不是一个好主意,建议使用已建立的数据访问框架或ORM以这种方式解析可选谓词和条件谓词。


或者,如果自己滚动,则where子句构建器应在代码中放在一个位置。然后,您可以在代码的单个位置处理零个谓词或多个零个谓词。我的怀疑是的存在WHERE 1=1是一个公平的指标,事实并非如此,代码库中散落着一些字符串WHERE 1=1,这对我来说是一个应用程序体系结构问题,我猜不是唯一一个!
杰森S

1
实际上,这个想法没有什么“坏”的东西,更不用说“明显的”错误了。在所有情况下,ORM都不是正确的方法。了解SQL和关系代数的人……
Hejazzman,

4

如果您是来这里搜索的WHERE 1,请注意WHERE 1WHERE 1=1相同。WHERE 1之所以很少使用它,是因为某些数据库系统考虑WHERE 1不是真正的布尔值而拒绝使用它。


2

在必须使用动态查询(其中必须在where子句中附加一些过滤器选项)的情况下,这很有用。就像您包含选项0表示状态为非活动,选择1表示活动那样。根据这些选项,只有两个可用的选项(0和1),但是如果要显示“所有记录”,可以方便地将它们包含在close = 1 = 1的位置。参见以下示例:

Declare @SearchValue    varchar(8) 
Declare @SQLQuery varchar(max) = '
Select [FirstName]
    ,[LastName]
    ,[MiddleName]
    ,[BirthDate]
,Case
    when [Status] = 0 then ''Inactive''
    when [Status] = 1 then ''Active''
end as [Status]'

Declare @SearchOption nvarchar(100)
If (@SearchValue = 'Active')
Begin
    Set @SearchOption = ' Where a.[Status] = 1'
End

If (@SearchValue = 'Inactive')
Begin
    Set @SearchOption = ' Where a.[Status] = 0'
End

If (@SearchValue = 'All')
Begin
    Set @SearchOption = ' Where 1=1'
End

Set @SQLQuery = @SQLQuery + @SearchOption

Exec(@SQLQuery);

2

复习了所有答案后,我决定进行一些实验,例如

SELECT
*
FROM MyTable

WHERE 1=1

然后我检查了其他数字

WHERE 2=2
WHERE 10=10
WHERE 99=99

ect完成所有检查后,查询运行镇是相同的。即使没有where子句。我不喜欢语法


1

我通常在为报表构建动态SQL时执行此操作,该报表具有用户可以选择的许多下拉值。由于用户可能会或可能不会从每个下拉列表中选择值,因此我们最终很难确定哪个条件是第一个where子句。因此,我们在查询where 1=1末尾添加a 并在其后添加所有where子句。

就像是

select column1, column2 from my table where 1=1 {name} {age};

然后我们将像这样构建where子句并将其作为参数值传递

string name_whereClause= ddlName.SelectedIndex > 0 ? "AND name ='"+ ddlName.SelectedValue+ "'" : "";

由于where子句选择在运行时对我们来说是未知的,因此这有助于我们找到是否包含一个 'AND' or 'WHERE'.


0

使用predicate这样的谓词1=1是通常用于强制访问计划使用或不使用索引扫描的常规提示。之所以使用此功能,是因为您在where子句中使用带有许多谓词的多嵌套联接查询,有时甚至使用所有索引也会导致访问计划读取每个表-全表扫描。这只是DBA用来诱使dbms使用更有效的路径的许多提示之一。只是不要扔进去;您需要一个dba来分析查询,因为它并不总是有效。


4
您是否有某些文献记录了某些数据库的这种行为?
2013年

0

这是一个用例...但是我不太关心为什么不应该使用1 = 1的技术性。我正在编写一个函数,使用pyodbc从SQL Server检索一些数据。我一直在寻找一种where在代码中的关键字后面强制填充符的方法。这确实是一个很好的建议:

if _where == '': _where = '1=1'
...
...
...
cur.execute(f'select {predicate} from {table_name} where {_where}')

原因是因为我无法在_where子句变量中一起实现关键字“ where”。因此,我认为使用任何评估为true的虚拟条件都可以作为填充条件。


-1

我首先使用ADO和经典ASP遇到了这个问题,我得到的答案是:性能。 如果你直

Select * from tablename

并将其作为sql命令/文本传递,随着

Where 1=1

添加,这是一个明显的区别。与满足第一个条件后立即返回表头有关,或者某种其他的疯狂,总之,它确实加快了速度。


3
如果是这样,那么DBMS为什么不总是添加它呢?
卡卡马诺

5
你能提供证据吗?
Peter G.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.