TL; DR:您必须限制所有文字,而不仅限于WHERE
子句中的文字。由于它们不这样做的原因,它允许数据库保持与其他系统的分离。
首先,您的前提存在缺陷。您只想限制WHERE
子句,但这不是用户输入可以进入的唯一位置。例如,
SELECT
COUNT(CASE WHEN item_type = 'blender' THEN 1 END) as type1_count,
COUNT(CASE WHEN item_type = 'television' THEN 1 END) AS type2_count)
FROM item
这同样容易受到SQL注入的攻击:
SELECT
COUNT(CASE WHEN item_type = 'blender' THEN 1 END) FROM item; DROP TABLE user_info; SELECT CASE(WHEN item_type = 'blender' THEN 1 END) as type1_count,
COUNT(CASE WHEN item_type = 'television' THEN 1 END) AS type2_count)
FROM item
因此,您不能只在WHERE
子句中限制文字。您必须限制所有文字。
现在剩下的问题是:“为什么根本不使用文字?” 请记住这一点:虽然在大多数情况下,关系数据库是在用另一种语言编写的应用程序下使用的,但并不要求必须使用应用程序代码才能使用该数据库。在这里,我们有一个答案:您需要文字来编写代码。唯一的其他选择是要求所有代码以某种独立于数据库的语言编写。因此拥有它们使您能够直接在数据库中编写“代码”(SQL)。这是很有价值的去耦,没有文字就不可能。(尝试在没有文字的情况下有时用自己喜欢的语言编写。我敢肯定,您可以想象这会有多困难。)
作为一个常见示例,常在值列表/查找表的填充中使用文字:
CREATE TABLE user_roles (role_id INTEGER, role_name VARCHAR(50));
INSERT INTO user_roles (1, 'normal');
INSERT INTO user_roles (2, 'admin');
INSERT INTO user_roles (3, 'banned');
没有它们,您仅需要使用另一种编程语言编写代码即可填充该表。直接在SQL中执行此操作的功能很有价值。
然后,我们还有一个问题:为什么编程语言客户端库不这样做呢?在这里,我们有一个非常简单的答案:他们将为每个受支持的数据库版本重新实现整个数据库解析器。为什么?因为没有其他方法可以保证您找到了所有文字。正则表达式还不够。例如:PostgreSQL中包含4个独立的文字:
SELECT $lit1$I'm a literal$lit1$||$lit2$I'm another literal $$ with nested string delimiters$$ $lit2$||'I''m ANOTHER literal'||$$I'm the last literal$$;
尝试这样做将是维护方面的噩梦,尤其是由于有效语法经常在主要版本的数据库之间更改时。
bad_ideas_sql = 'SELECT title FROM idea WHERE idea.status == "bad" AND idea.user == :mwheeler'
在单个查询中将同时具有硬编码和参数化的值–尝试抓住这一点!我认为此类混合查询有有效的用例。