同一列上的多个 AND 条件 [Servicestack.OrmLite]

Multiple AND conditions on the same column [Servicestack.OrmLite]

我想知道是否可以使用 Servicestack.OrmLite 在同一列上设置多个 AND 条件。这是我打印出来的 SELECT 语句,但它总是 returns 0。我应该从具有 id 1016 和 17 两种规格的产品中获取产品计数。

SELECT COUNT(DISTINCT "Product"."Id") 
FROM "Product" 
INNER JOIN "ProductManufacturer" 
ON ("Product"."Id" = "ProductManufacturer"."ProductId") 
INNER JOIN "ProductSpecificationAttribute" 
ON ("Product"."Id" = "ProductSpecificationAttribute"."ProductId")
WHERE ("ProductManufacturer"."ManufacturerId" = 6) 
AND ("ProductSpecificationAttribute"."SpecificationAttributeOptionId" = 1016) 
AND ("ProductSpecificationAttribute"."SpecificationAttributeOptionId" = 17)

一个列值不可能同时有两个值。

你想要的是:

AND
(
  ProductSpecificationAttribute.SpecificationAttributeOptionId = 1016
  OR  
  ProductSpecificationAttribute.SpecificationAttributeOptionId = 17
)

或者,更简洁:

AND
(
  ProductSpecificationAttribute.SpecificationAttributeOptionId 
  IN (1016, 17)
)

并关闭任何强制您的工具“注入”“双”“引号”“周围”“每个”“实体”“名称”的选项,因为它会使查询文本难以管理。您还可以考虑使用别名和架构前缀,例如 INNER JOIN dbo.ProductSpecificationAttribute AS psa...

进一步澄清后...目标是找到在不同行上同时具有这两个属性的产品,这在描述或代码 ORMLite 中并不清楚吐出来了。在这种情况下,这就是您想要的(有几种方法可以做到这一点,但是将所有内容转换为 EXISTS 还允许您从 COUNT 中删除 DISTINCT,这永远不会免费):

SELECT COUNT(Product.Id) FROM dbo.Product AS p
WHERE EXISTS
(
  SELECT 1 FROM dbo.ProductManufacturer AS pm 
    WHERE pm.ProductId = p.Id AND pm.ManufacturerId = 6
)
AND EXISTS
(
  SELECT 1 FROM dbo.ProductSpecificationAttribute AS psa
    WHERE psa.ProductId = p.Id
    AND psa.SpecificationAttributeOptionId = 1016
)
AND EXISTS
(
  SELECT 1 FROM dbo.ProductSpecificationAttribute AS psa
    WHERE psa.ProductId = p.Id
    AND psa.SpecificationAttributeOptionId = 17
);

如果 ProductSpecificationAttribute 的索引很差,这会导致两次扫描,您可以通过这样说来更改它(未经测试,但如果可以的话,我很乐意测试一下 produce a db<>fiddle :

SELECT COUNT(Product.Id) FROM dbo.Product AS p
WHERE EXISTS
(
  SELECT 1 FROM dbo.ProductManufacturer AS pm 
    WHERE pm.ProductId = p.Id 
    AND pm.ManufacturerId = 6
)
AND EXISTS
(
  SELECT 1 FROM dbo.ProductSpecificationAttribute AS psa
    WHERE psa.ProductId = p.Id
    AND psa.SpecificationAttributeOptionId IN (17, 1016)
    GROUP BY psa.ProductId, psa.SpecificationAttributeOptionId
    HAVING COUNT(DISTINCT psa.SpecificationAttributeOptionId) > 1
);

table ProductManufacturer 中有一个指向 ProductProductID 列表也很奇怪——通常 Product 会有一个 ManufacturerID 指向另一个方向。

无论如何,如果 ORM 在创建基本 CRUD 之外的查询时遇到问题,您可以考虑使用 ORM 可以调用的存储过程(不幸的是,这在某种程度上是所有 ORM 的局限性 - 它们在基础知识方面非常出色,涵盖 80 % 的用例,但其他 20% 的情况很糟糕 - 不幸的是,我们大多数人很快就会需要另外 20%。

按商品分组,在HAVING子句中设置条件,即可得到所有想要的商品id:

SELECT p.Id
FROM Product p
INNER JOIN ProductManufacturer pm ON p.Id = pm.ProductId 
INNER JOIN ProductSpecificationAttribute psa ON p.Id = psa.ProductId
WHERE pm.ManufacturerId = 6 AND psa.SpecificationAttributeOptionId IN (17, 1016)
GROUP BY p.Id
HAVING COUNT(DISTINCT psa.SpecificationAttributeOptionId) = 2; -- both specifications must exist

如果您想计算这些产品,您可以将上述查询用作子查询或 cte 并计算行数:

WITH cte AS (
  SELECT p.Id
  FROM Product p
  INNER JOIN ProductManufacturer pm ON p.Id = pm.ProductId 
  INNER JOIN ProductSpecificationAttribute psa ON p.Id = psa.ProductId
  WHERE pm.ManufacturerId = 6 AND psa.SpecificationAttributeOptionId IN (17, 1016)
  GROUP BY p.Id
  HAVING COUNT(DISTINCT psa.SpecificationAttributeOptionId) = 2; 
)
SELECT COUNT(*) FROM cte;

或者,使用 COUNT() window 函数:

SELECT DISTINCT COUNT(*) OVER ()
FROM Product p
INNER JOIN ProductManufacturer pm ON p.Id = pm.ProductId 
INNER JOIN ProductSpecificationAttribute psa ON p.Id = psa.ProductId
WHERE pm.ManufacturerId = 6 AND psa.SpecificationAttributeOptionId IN (17, 1016)
GROUP BY p.Id
HAVING COUNT(DISTINCT psa.SpecificationAttributeOptionId) = 2;