SQL 服务器:使用多个 AND 和 OR 进行内部联接

SQL Server : inner join with multiple ANDs and ORs

每个产品都有 LatLng。随着时间的推移,有时产品可以复制,但很难发现。价格或图片可能略有不同。

我想比较 Products 每个位置的 ProductTypePrice 并将它们放在地图上以便更容易找到重复项。

对于每个产品,我计算其价格的 5%,这样我就可以 add/subtract 从其他产品价格中找到大致匹配的。

Products

ProductID ProductType Price Latitude Longitude
ABC Red Widget 500 12.34 67.89
DEF Red Widget 505 12.34 67.89
MNO Red Widget 480 12.34 67.89
RST Red Widget 500 12.34 67.89
UVW Red Widget 300 12.34 67.89
JKL Blue Widget 800 76.54 32.10
XYZ Blue Widget 800 45.67 23.45

预期的结果是应该返回ABCDEFMNO AND RST,因为它们都是Red Widgets,在同一个位置和价格要么完全相同,要么价格相差在彼此价格的 5% 以内。

UVW 超出百分比,因此可能不是重复项,不应返回。

JKLXYZBlue Widgets 价格相同,但不在同一地点,因此不退货。

SQL

这是我目前所拥有的,但它返回的结果太多了。我认为它会返回在每个位置之外匹配的行。 JOIN 中的 AND 在我看来是正确的。感觉 OR 可能允许更灵活的匹配,但括号看起来正确...

WITH cte AS
(
    SELECT 
        p.ProductID,
        p.ProductType,
        p.Price,
        (p.Price / 100) * 5 AS PricePercent,
        ROUND(p.Latitude, 3) AS Latitude,
        ROUND(p.Longitude, 3) AS Longitude
    FROM 
        Products p
    WHERE
       p.Latitude IS NOT NULL AND p.Longitude IS NOT NULL 
)
SELECT 
    DISTINCT a.ProductID,
    a.Price,
    a.Latitude, a.Longitude
FROM 
    cte a
INNER JOIN 
    /* ProductIDs don't match */
    cte b ON a.ProductID <> b.ProductID
    /* match only where location is the same*/
          AND a.Latitude = b.Latitude 
          AND a.Longitude = b.Longitude
    /* match only where Product Type is the same*/
          AND a.ProductType = b.ProductType
    /*match only if price is the same, or within 5% above or 5% below price*/
          AND (/*same price*/
               b.Price = a.Price 
               OR
               /*b.price is within percentage over a.price*/
               (b.Price > a.Price AND b.Price < (a.Price+a.PricePercent))
               OR
               /*b.price is within percentage under a.price */
               (b.Price < a.Price AND b.Price >(a.Price-a.PricePercent)))

首先这件事:

AND (/*same price*/
                   b.Price = a.Price 
                   OR
                   /*b.price is within percentage over a.price*/
                   (b.Price > a.Price AND b.Price < (a.Price+a.PricePercent))
                   OR
                   /*b.price is within percentage under a.price */
                   (b.Price < a.Price AND b.Price >(a.Price-a.PricePercent))
           )

与(或应该)相同:

AND (
    -- price within range +/- percent
    b.Price < (a.Price+a.PricePercent) 
    AND b.Price >(a.Price-a.PricePercent)
    )

其次对我有用:

SQL Fiddle

MS SQL Server 2017 架构设置:

查询 1:

WITH cte AS
    (
        SELECT 
            p.ProductID,
            p.ProductType,
            p.Price,
            (p.Price / 100) * 5 AS PricePercent,
            ROUND(p.Latitude, 3) AS Latitude,
            ROUND(p.Longitude, 3) AS Longitude
        FROM 
            Products p
        WHERE
           p.Latitude IS NOT NULL AND p.Longitude IS NOT NULL 
    )
    SELECT 
        DISTINCT a.ProductID,
        a.Price,
        a.Latitude, a.Longitude
    FROM 
        cte a
    INNER JOIN 
        /* ProductIDs don't match */
        cte b ON a.ProductID <> b.ProductID
        /* match only where location is the same*/
              AND a.Latitude = b.Latitude 
              AND a.Longitude = b.Longitude
        /* match only where Product Type is the same*/
              AND a.ProductType = b.ProductType
        /*match only if price is the same, or within 5% above or 5% below price*/
              AND (
        -- price within range +/- percent
        b.Price < (a.Price+a.PricePercent) 
        AND b.Price >(a.Price-a.PricePercent)
     )

Results:

ProductID Price Latitude Longitude
ABC 500 12 68
DEF 505 12 68
RST 500 12 68