SQL SELECT多条件多对多关系

时间:2015-06-12 19:28:26

标签: sql sql-server sql-server-2008

我正在努力寻找这个问题的优雅解决方案。 我有5个表,它们的关系在图像中描述。 enter image description here

页面可以包含多个产品,每个产品可以包含许多ProductRates。具有特定产品的页面也可以具有多个速率。为了解决许多问题,有表PageToProductToRate。

用户希望查询多个条件,其中选择可以是任意组合:

  • 产品1 +费率1 +费率属性1
  • Product1 + Rate1 + rate attribute2
  • 产品1 +费率2 +费率属性2
  • 产品2 +费率3 +费率属性1等......

这是数据和WHERE条件和预期结果的示例: enter image description here

另一个: enter image description here

适合我的查询使用INTERSECT来获得正确的结果。我尝试过UNION但会得到不符合所有条件的结果。

SELECT DISTINCT P.[PageID]
FROM [Page] P
  join PageToProduct p2p on p2p.[PageID] = P.[PageID] 
  join Product pr on p2p.[Product] = pr.[Product] 
  join PageToProductToRate p2p2r on p2p2r.[PageToProductID] = p2p.[PageToProductID] 
  join ProductRates r on r.[ProductRatesID] = p2p2r.[ProductRatesID] 
  WHERE (PR.[Product] = 'ALMOND' AND R.CommissionType = 'PREMIUM' AND R.Rate = 0.25) 
INTERSECT
SELECT DISTINCT P.[PageID]
FROM [Page] P
  join PageToProduct p2p on p2p.[PageID] = P.[PageID] 
  join Product pr on p2p.[Product] = pr.[Product] 
  join PageToProductToRate p2p2r on p2p2r.[PageToProductID] = p2p.[PageToProductID] 
  join ProductRates r on r.[ProductRatesID] = p2p2r.[ProductRatesID] 
  WHERE (PR.[Product] = 'WALNUT' AND R.CommissionType = 'SERVICE FEE' AND R.Rate = 1.25)
INTERSECT
SELECT DISTINCT P.[PageID]
FROM [Page] P
  join PageToProduct p2p on p2p.[PageID] = P.[PageID] 
  join Product pr on p2p.[Product] = pr.[Product] 
  join PageToProductToRate p2p2r on p2p2r.[PageToProductID] = p2p.[PageToProductID] 
  join ProductRates r on r.[ProductRatesID] = p2p2r.[ProductRatesID] 
  WHERE (PR.[Product] = 'HAZELNUT' AND R.CommissionType = 'EXCESS' AND R.Rate = 1.68)

有没有更好的方法来解决这个问题?我可能有十几个这样的条件,并且所有连接的查询可能会失控。

3 个答案:

答案 0 :(得分:1)

我最好的猜测。

WITH products AS 
(
    SELECT  [Product],
            [ProductRatesID]
    FROM    Product p
            JOIN ProductRates pr ON p.[Product] = pr.[Product]
    WHERE   (p.[Product] = 'ALMOND' AND pr.CommissionType = 'PREMIUM' AND pr.Rate = 0.25)
            OR (p.[Product] = 'WALNUT' AND pr.CommissionType = 'SERVICE FEE' AND pr.Rate = 1.25)
            OR (p.[Product] = 'HAZELNUT' AND pr.CommissionType = 'EXCESS' AND pr.Rate = 1.68)
)
SELECT  P.[PageID]
FROM    [Page] P
        JOIN (
            SELECT  p2p.[PageID], COUNT(*) as ProductCount
            FROM    products pr
                    JOIN PageToProduct p2p ON p2p.[Product] = pr.[Product]
                    JOIN PageToProductToRate p2p2r on p2p2r.[PageToProductID] = p2p.[PageToProductID] 
            WHERE   p2p2r.[ProductRatesID] = pr.[ProductRatesID]
            GROUP BY p2p.[PageID]
        ) sq ON sq.[PageID] = p.[PageID]
WHERE   sq.ProductCount = @ProductFilterCount

您需要弄清楚如何处理@ProductFilterCount。它可以是您正在使用的数字过滤器的数量,也可以是实际匹配这些过滤器的产品数量

SQL Fiddle

答案 1 :(得分:1)

SELECT p2p.PageID
FROM
    PageToProduct as p2p
    inner join Product as pr
        on p2p.Product = pr.Product
    inner join PageToProductToRate as p2p2r
        on p2p2r.PageToProductID = p2p.PageToProductID
    inner join ProductRates as r
        on r.ProductRatesID = p2p2r.ProductRatesID 
WHERE
          (pr.Product = 'ALMOND' AND r.CommissionType = 'PREMIUM' AND r.Rate = 0.25) 
      OR  (pr.Product = 'WALNUT' AND r.CommissionType = 'SERVICE FEE' AND r.Rate = 1.25)
      OR  (pr.Product = 'HAZELNUT' AND r.CommissionType = 'EXCESS' AND r.Rate = 1.68)
GROUP BY p2p.PageID
HAVING COUNT(*) = 3; /* requires all three are present, as long as no rows are duplicate */

答案 2 :(得分:0)

我不确定你要问的是什么......但是如果你想要有产品选择的页面然后这可能有用,你就必须自己测试

编辑 - 改为AND,因为他希望满足所有条件

SELECT DISTINCT P.[PageID]
FROM [Page] P
  join PageToProduct p2p on p2p.[PageID] = P.[PageID] 
  join Product pr on p2p.[Product] = pr.[Product] 
  join PageToProductToRate p2p2r on p2p2r.[PageToProductID] = p2p.[PageToProductID] 
  join ProductRates r on r.[ProductRatesID] = p2p2r.[ProductRatesID] 
  WHERE (PR.[Product] = 'ALMOND' AND R.CommissionType = 'PREMIUM' AND R.Rate = 0.25) 
  AND (PR.[Product] = 'WALNUT' AND R.CommissionType = 'SERVICE FEE' AND R.Rate = 1.25)
  AND (PR.[Product] = 'HAZELNUT' AND R.CommissionType = 'EXCESS' AND R.Rate = 1.68)