如何在 pg-promise 中正确编写带有空约束的查询?
How do I write queries with a null constraint in pg-promise properly?
在编写 Postgres 查询时,约束通常写成这样
WHERE a = $(a)
或 WHERE b IN $(b:csv)
如果您知道它是一个列表。但是,如果值为 null
,则必须将约束写入 WHERE x IS NULL
。如果值为 null 或不为空,是否可以让查询自动格式化?
假设我可能想要查找行 WHERE c = 1
。如果我知道 c
是 1
,我将查询写成
db.oneOrNone(`SELECT * FROM blah WHERE c = $(c), { c })
但是如果 c
结果是 null
,查询就必须变成 ...WHERE c IS NULL
。
是否可以构造一个像WHERE $(c)
这样的通用查询,如果c
是1
,它会自动格式化为WHERE c = 1
,而WHERE c IS NULL
如果 c
设置为 null?
您可以使用 Custom Type Formatting 来帮助进行动态查询:
const valueOrNull = (col, value) => ({
rawType: true,
toPostgres: () => pgp.as.format(`:name ${value === null ? 'IS NULL' : '= '}`,
[col, value])
});
然后你可以把它作为格式化值传入:
db.oneOrNone('SELECT * FROM blah WHERE $[cnd]', { cnd: valueOrNull('col', 123) })
更新
或者您可以仅为值本身使用自定义格式:
const eqOrNull = value => ({
rawType: true,
toPostgres: () => pgp.as.format(`${value === null ? 'IS NULL' : '= '}`, value)
});
用法示例:
db.oneOrNone('SELECT * FROM blah WHERE :name ', ['col', eqOrNull(123)])
//=> SELECT * FROM blah WHERE "col" = 123
db.oneOrNone('SELECT * FROM blah WHERE :name ', ['col', eqOrNull(null)])
//=> SELECT * FROM blah WHERE "col" IS NULL
请注意,为简单起见,我没有包含对 undefined
的检查,但您很可能会这样做,因为 undefined
在内部也被格式化为 null
。
根据值是否为 NULL
修改查询的一个非常有用的替代方法是使用 IS [NOT] DISTINCT FROM
。来自参考:
For non-null inputs, IS DISTINCT FROM
is the same as the <>
operator. However, if both inputs are null it returns false, and if only one input is null it returns true. Similarly, IS NOT DISTINCT FROM
is identical to =
for non-null inputs, but it returns true when both inputs are null, and false when only one input is null. Thus, these predicates effectively act as though null were a normal data value, rather than “unknown”.
简而言之,用IS NOT DISTINCT FROM
代替=
,用IS DISTINCT FROM
代替<>
。
这在比较两列时特别有用,其中任何一列都可能为空。
请注意 IS [NOT] DISTINCT FROM
不能使用索引,因此某些查询可能执行不佳。
在编写 Postgres 查询时,约束通常写成这样
WHERE a = $(a)
或 WHERE b IN $(b:csv)
如果您知道它是一个列表。但是,如果值为 null
,则必须将约束写入 WHERE x IS NULL
。如果值为 null 或不为空,是否可以让查询自动格式化?
假设我可能想要查找行 WHERE c = 1
。如果我知道 c
是 1
,我将查询写成
db.oneOrNone(`SELECT * FROM blah WHERE c = $(c), { c })
但是如果 c
结果是 null
,查询就必须变成 ...WHERE c IS NULL
。
是否可以构造一个像WHERE $(c)
这样的通用查询,如果c
是1
,它会自动格式化为WHERE c = 1
,而WHERE c IS NULL
如果 c
设置为 null?
您可以使用 Custom Type Formatting 来帮助进行动态查询:
const valueOrNull = (col, value) => ({
rawType: true,
toPostgres: () => pgp.as.format(`:name ${value === null ? 'IS NULL' : '= '}`,
[col, value])
});
然后你可以把它作为格式化值传入:
db.oneOrNone('SELECT * FROM blah WHERE $[cnd]', { cnd: valueOrNull('col', 123) })
更新
或者您可以仅为值本身使用自定义格式:
const eqOrNull = value => ({
rawType: true,
toPostgres: () => pgp.as.format(`${value === null ? 'IS NULL' : '= '}`, value)
});
用法示例:
db.oneOrNone('SELECT * FROM blah WHERE :name ', ['col', eqOrNull(123)])
//=> SELECT * FROM blah WHERE "col" = 123
db.oneOrNone('SELECT * FROM blah WHERE :name ', ['col', eqOrNull(null)])
//=> SELECT * FROM blah WHERE "col" IS NULL
请注意,为简单起见,我没有包含对 undefined
的检查,但您很可能会这样做,因为 undefined
在内部也被格式化为 null
。
根据值是否为 NULL
修改查询的一个非常有用的替代方法是使用 IS [NOT] DISTINCT FROM
。来自参考:
For non-null inputs,
IS DISTINCT FROM
is the same as the<>
operator. However, if both inputs are null it returns false, and if only one input is null it returns true. Similarly,IS NOT DISTINCT FROM
is identical to=
for non-null inputs, but it returns true when both inputs are null, and false when only one input is null. Thus, these predicates effectively act as though null were a normal data value, rather than “unknown”.
简而言之,用IS NOT DISTINCT FROM
代替=
,用IS DISTINCT FROM
代替<>
。
这在比较两列时特别有用,其中任何一列都可能为空。
请注意 IS [NOT] DISTINCT FROM
不能使用索引,因此某些查询可能执行不佳。