为什么有人会在 SQL 子句中使用 WHERE 1=1 AND <conditions>
(通过连接字符串获得的 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
如果条件列表在编译时未知,而是在运行时构建,则您不必担心是否有一个或多个条件。你可以像这样生成它们:
and <condition>
并将它们连接在一起。以 1=1
开头,最初的 and
有一些关联。
我从未见过它用于任何类型的注射保护,正如你所说,它似乎没有多大帮助。我已经看到它被用作实现便利。 SQL 查询引擎最终会忽略 1=1
,因此它不会对性能产生影响。
只需在 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
我已经看到当条件的数量可以变化时使用它。
您可以使用“AND”字符串连接条件。然后,不是计算您传入的条件的数量,而是在您的股票 SQL 语句的末尾放置一个“WHERE 1=1”并抛出连接的条件。
基本上,它使您不必对条件进行测试,然后在它们之前添加一个“WHERE”字符串。
总是知道您的 WHERE 子句已定义并允许您继续添加条件而无需检查它是否是第一个条件,这似乎是一种懒惰的方式。
where 1=1
(Oracle) 或 where true
(Postgres),我将不得不检查每个条件是否是第一个条件。这样做没有意义,它只会添加更多样板代码。
WHERE 1=1
产生了在多个位置维护相同代码并在所有生成的 SQL 中读取它的额外工作。我比你想象的还要懒!
间接相关:当使用 1=2 时:
CREATE TABLE New_table_name
as
select *
FROM Old_table_name
WHERE 1 = 2;
这将创建一个与旧表具有相同架构的新表。 (如果您想加载一些数据进行比较,非常方便)
= 1 表达式常用于生成的 sql 代码中。该表达式可以简化 sql 生成代码,减少条件语句的数量。
当我在数据库上测试或仔细检查事物时,我发现这种模式很有用,因此我可以非常快速地评论其他条件:
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
实际上,我已经在 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
where 1=1
(Oracle) 或 where true
(Postgres),我将不得不检查每个条件是否是第一个条件。这样做没有意义,它只会添加更多样板代码。
其中 1=0,这样做是为了检查表是否存在。不知道为什么使用 1=1。
虽然我可以看到 1=1 对于生成的 SQL 很有用,但我在 PHP 中使用的一种技术是创建一个子句数组,然后执行
implode (" AND ", $clauses);
从而避免出现前导或尾随 AND 的问题。显然,这仅在您知道您将拥有至少一个子句时才有用!
这是一个密切相关的示例:使用 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;
如果您来这里搜索 WHERE 1
,请注意 WHERE 1
和 WHERE 1=1
是相同的。 WHERE 1
很少使用,因为某些数据库系统认为 WHERE 1
不是真正的布尔值而拒绝它。
为什么有人会使用 WHERE 1=1 AND
我有 seen 个自制框架做这样的事情 (blush),因为这允许将惰性解析实践应用于 WHERE
和 AND
Sql 关键字。
例如(我在这里使用 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 1=1
的存在是一个公平的指标,表明情况并非如此,代码库中到处都是字符串 WHERE 1=1
,这对我来说表明存在应用程序架构问题,我猜不是唯一的!
查看所有答案后,我决定进行一些实验,例如
SELECT
*
FROM MyTable
WHERE 1=1
然后我检查了其他号码
WHERE 2=2
WHERE 10=10
WHERE 99=99
ect 完成所有检查后,查询运行城镇是相同的。即使没有 where 子句。我不喜欢语法
这在您必须使用动态查询的情况下很有用,其中在 where 子句中您必须附加一些过滤器选项。就像如果您包含选项 0 状态为非活动状态,1 为活动状态。根据选项,只有两个可用选项(0 和 1),但如果要显示所有记录,可以方便地包含在 where 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);
在生产代码中看到这个,请前辈帮忙。
他们的回答:
- 我们使用 1=1 所以当我们必须添加一个新条件时,我们可以输入
and <condition>
继续做下去。
我通常在为具有许多用户可以选择的下拉值的报表构建动态 SQL 时这样做。由于用户可能会或可能不会从每个下拉列表中选择值,因此我们最终很难确定哪个条件是第一个 where 子句。所以我们最后用 where 1=1
填充查询,然后添加所有 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'.
使“where 1=1”成为所有查询的标准还可以通过将其替换为 where 1 = 0 来轻松验证 sql,这在您有成批的命令/文件时很方便。
还可以很容易地找到任何查询的 from/join 部分的结尾。如果缩进正确,即使是带有子查询的查询。
我第一次遇到这个是用 ADO 和经典的 asp,我得到的答案是:性能。如果你做一个直线
Select * from tablename
并将其作为 sql 命令/文本传递,您将获得显着的性能提升
Where 1=1
补充说,这是一个明显的差异。与第一个条件满足后立即返回表头有关,或者其他一些疯狂的事情,无论如何,它确实加快了速度。
使用像 1=1
这样的谓词是一个正常的提示,有时用于强制访问计划使用或不使用索引扫描。使用它的原因是当您在 where 子句中使用具有许多谓词的多嵌套连接查询时,有时即使使用所有索引也会导致访问计划读取每个表 - 全表扫描。这只是 DBA 用来欺骗 dbms 使用更有效路径的众多提示之一。只是不要扔进去;您需要一个 dba 来分析查询,因为它并不总是有效。
这是一个用例......但是我不太关心为什么我应该使用或不使用 1 = 1 的技术细节。我正在编写一个函数,使用 pyodbc 从 SQL Server 检索一些数据。我正在寻找一种在我的代码中的 where
关键字之后强制填充的方法。这确实是一个很好的建议:
if _where == '': _where = '1=1'
...
...
...
cur.execute(f'select {predicate} from {table_name} where {_where}')
原因是我无法在 _where 子句变量中同时实现关键字“where”。所以,我认为使用任何评估为 true 的虚拟条件都可以作为填充物。
不定期副业成功案例分享
where 1=1
(Oracle) 或where true
(Postgres),我将不得不检查每个条件是否是第一个条件。这样做没有意义,它只会添加更多样板代码。