WHERE IN 使用 Azure DocumentDB (CosmosDB) .Net SDK
WHERE IN with Azure DocumentDB (CosmosDB) .Net SDK
看过 this question 我不确定为什么 我的 DocDb 实例的以下代码不起作用:
var userApps = _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameters()))
.ToList()
.Select(s => (string)s.appId);
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec(@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN (@userApps)", (@"@userApps", userApps.ToArray()).ToSqlParameters()),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
当我执行这个时,虽然我知道数据应该返回一个结果集,但每次返回都是空的。
到目前为止的故障排除
.Select()
的变体
Return 我 string.Join
到逗号分隔列表中的字符串。
例如:
var userApps = string.Join(@",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameters()))
.ToList()
.Select(s => $@"'{s.appId}'");
不封装IN参数
删除查询中参数规范周围的 () 认为 SqlParameter 规范可能正在执行数组规范?
例如:@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN @userApps"
)
最终抛出 "Syntax error, incorrect syntax near '@userApps'."
通过 Azure 门户查询验证
运行 这个代码应该是 运行.
的(预期的)SQL
我毫无问题地得到了我的预期结果(即:我知道这些查询有一个写成的结果集)。
查询 1 的调试器输出
AppIds 从查询 1 返回。
不令人满意的解决方法
将查询 2 更改为 不 参数化。相反,将查询 1 中以逗号分隔的 ID 列表注入其中:
var userApps = string.Join(@",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameter()))
.ToList()
.Select(s => $@"'{s.appId}'"));
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec($@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN ({userApps})"),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
工作完美,但我不会接受它作为这个问题的答案,因为它违背了几十年的 SQL 最佳实践,坦率地说,不应该t 是一个解决方案。
这是我的 ToSqlParameters()
扩展方法,以防它是罪魁祸首(不过,这在我用过的其他任何地方都有效。数组可能需要一些特殊的东西?):
public static SqlParameterCollection ToSqlParameters(this (string, object) parmDef) => new SqlParameterCollection(new[] { new SqlParameter(parmDef.Item1, parmDef.Item2) });
谢谢!
如果你使用参数化的IN列表,那么当参数展开时它会被认为是一个单一的值。
例如,对于这个查询:
SELECT * FROM r WHERE r.item IN (@items) And @items is defined as "['val1', 'val2', 'val3']"
将被解释为:
SELECT * FROM r WHERE r.item IN (['val1', 'val2', 'val3'])
这基本上意味着您将 r.item 与一个包含三个元素的数组的单个值进行比较(即相当于 r.item = ['val1', 'val2', 'val3'])
.
要与多个项目进行比较,您需要为每个值使用一个参数。像这样:SELECT * FROM r WHERE r.item IN (@val1, @val2, @val3])
编写此查询的更方便的方法是改用 ARRAY_CONTAINS 并将项目数组作为单个参数传递。所以上面的查询会这样写:
SELECT * FROM r WHERE ARRAY_CONTAINS(@items, r.item)
看过 this question 我不确定为什么 我的 DocDb 实例的以下代码不起作用:
var userApps = _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameters()))
.ToList()
.Select(s => (string)s.appId);
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec(@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN (@userApps)", (@"@userApps", userApps.ToArray()).ToSqlParameters()),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
当我执行这个时,虽然我知道数据应该返回一个结果集,但每次返回都是空的。
到目前为止的故障排除
.Select()
的变体
Return 我 string.Join
到逗号分隔列表中的字符串。
例如:
var userApps = string.Join(@",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameters()))
.ToList()
.Select(s => $@"'{s.appId}'");
不封装IN参数
删除查询中参数规范周围的 () 认为 SqlParameter 规范可能正在执行数组规范?
例如:@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN @userApps"
)
最终抛出 "Syntax error, incorrect syntax near '@userApps'."
通过 Azure 门户查询验证
运行 这个代码应该是 运行.
的(预期的)SQL我毫无问题地得到了我的预期结果(即:我知道这些查询有一个写成的结果集)。
查询 1 的调试器输出
AppIds 从查询 1 返回。
不令人满意的解决方法
将查询 2 更改为 不 参数化。相反,将查询 1 中以逗号分隔的 ID 列表注入其中:
var userApps = string.Join(@",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameter()))
.ToList()
.Select(s => $@"'{s.appId}'"));
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec($@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN ({userApps})"),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
工作完美,但我不会接受它作为这个问题的答案,因为它违背了几十年的 SQL 最佳实践,坦率地说,不应该t 是一个解决方案。
这是我的 ToSqlParameters()
扩展方法,以防它是罪魁祸首(不过,这在我用过的其他任何地方都有效。数组可能需要一些特殊的东西?):
public static SqlParameterCollection ToSqlParameters(this (string, object) parmDef) => new SqlParameterCollection(new[] { new SqlParameter(parmDef.Item1, parmDef.Item2) });
谢谢!
如果你使用参数化的IN列表,那么当参数展开时它会被认为是一个单一的值。
例如,对于这个查询:
SELECT * FROM r WHERE r.item IN (@items) And @items is defined as "['val1', 'val2', 'val3']"
将被解释为:
SELECT * FROM r WHERE r.item IN (['val1', 'val2', 'val3'])
这基本上意味着您将 r.item 与一个包含三个元素的数组的单个值进行比较(即相当于 r.item = ['val1', 'val2', 'val3'])
.
要与多个项目进行比较,您需要为每个值使用一个参数。像这样:SELECT * FROM r WHERE r.item IN (@val1, @val2, @val3])
编写此查询的更方便的方法是改用 ARRAY_CONTAINS 并将项目数组作为单个参数传递。所以上面的查询会这样写:
SELECT * FROM r WHERE ARRAY_CONTAINS(@items, r.item)