【问题标题】:Self-joining table and matching multiple rows自联接表和匹配多行
【发布时间】:2016-12-02 16:31:10
【问题描述】:

考虑以下多对多表:

FK_Composition | FK_Part | Position | Quantity
---------------+---------+----------+---------
101            | 2001    | -3       | 1
101            | 2002    | -2       | 2
101            | 2003    | -1       | 1
101            | 2011    |  0       | 1
102            | 2001    | -2       | 1
102            | 2002    | -1       | 2
102            | 2003    |  0       | 1
102            | 2012    |  1       | 1

目标是通过比较找到与某个构图几乎相同的构图。 “差不多”的意思:

  1. 比较的构图由与原始部分相同的部分组成,除了位置最高的部分
  2. 所有部分都必须位于相同的相对位置(在将合成与位置 [-1,0, 1,2])
  3. 每个出现的部分都应具有相同的数量
  4. 比较的作品没有比原始作品更多的部分

按照这些规则,作文 102几乎与 101 相同。

当然,我的问题更有趣:我们的实体框架只允许使用简单的 SELECT 查询并且我们应该同时支持 SQL Server 数据库以及访问“数据库” ”。查询应该同时支持系统和临时表,循环是不行的。

我使用不同的数据库已经有一段时间了,但我不记得我以前曾像这样在自联接中匹配多行中的多个值。然而,我认为有理由认为应该有一个简单的方法来实现这一点。有吗?

额外问题:我正在考虑在 .NET 应用程序中以不同的部分查询我需要的数据,并让 Linq 发挥作用,但有人担心某些客户的计算机可能无法很好地处理过多的内存数据.我们谈论的数据可能多达一百万行,具体取决于客户的数据库。这是一个有效的担忧吗?

编辑 - 根据 cmets 的要求,以下是一些反例,其中的构图与构图 101 相比不应匹配:

FK_Composition | FK_Part | Position | Quantity | Reason
---------------+---------+----------+----------+------
151            | 2001    | -3       | 1        | Part 2004 is no match
151            | 2002    | -2       | 2        | 
151            | 2004    | -1       | 1        | 
151            | 2011    |  0       | 1        | 
152            | 2001    | -2       | 1        | Has a different number of parts
152            | 2002    | -1       | 2        | 
152            | 2012    |  0       | 1        | 
153            | 2001    |  1       | 2        | Position 1 has the wrong quantity
153            | 2002    |  2       | 2        | 
153            | 2004    |  3       | 1        | 
153            | 2011    |  4       | 1        | 

【问题讨论】:

  • 您可能应该添加更多测试用例来解释其他一些细微差别。例如它们是否也必须具有相同数量的零件?例如。如果 103 有 6 个部分并且前 3 个匹配 101 中的前 3 个会是一个紧密匹配吗?
  • 我认为 1) 是说它们必须具有相同的部分(最高位置除外)。但我同意更多的例子会很有帮助——至少是一个不匹配的反例。您还会得到一组不连续的位置,例如(1,2,2,3) 还是 (1,3,6578)?最高部分的数量需要匹配吗?
  • @Matt 是的,它们的零件数量相同。职位的数量和每个职位的数量都必须匹配。
  • @JamesCasey 据我所知,它们不应该是一组不连续的位置。至少它们不能是 (1,2,2,3) 之类的东西,因为该位置是主键的一部分。最高部分的数量需要匹配。

标签: c# sql sql-server ms-access subquery


【解决方案1】:

这是一个 sql-server 版本。这在 ms-access 中不起作用,老实说,所有子查询和派生表以及在 msa-access 中执行此操作所必需的东西都不会让我对写抱歉感兴趣。但它应该让你对一些逻辑等有所了解。

http://rextester.com/FSJG1811 示例显示它的工作原理

DECLARE @Table AS TABLE (FKComposition INT, FKPart INT, Position INT, Quantity INT)
INSERT INTO @Table VALUES (101,2001,-3,1),(101,2002,-2,2),(101,2003,-1,1),(101,2011, 0,1)
,(102,2001,-2,1),(102,2002,-1,2),(102,2003, 0,1),(102,2012, 1,1) -- 3 of 4 match but not the highest position
,(103,2002,-2,1),(103,2003,-1,2),(103,2004, 0,1),(103,2012, 1,1) -- 3 of 4 match but not 1 of the middle positions
,(104,2001,-2,1) --match but last and highes position
,(105,2001,-3,1),(105,2002,-2,2),(105,2003,-1,1),(105,2011, 0,1) --exact match
,(106,2001,-5,1),(106,2002,-2,2),(106,2003,-1,1),(106,2011, 0,1) --exact match except PositionDifference

;WITH cte AS (
    SELECT
       *
       ,ROW_NUMBER() OVER (PARTITION BY FKComposition ORDER BY Position) as PosRowNum
       ,Position - COALESCE(LAG(Position) OVER (PARTITION BY FKComposition ORDER BY Position),Position) as PosDif
       ,COUNT(*) OVER (PARTITION BY FKcomposition) as PartsCount
       ,MAX(Position) OVER (PARTITION BY FKComposition) as HighestPosition
    FROM
       @Table
)

    SELECT
       CASE WHEN c1.FKComposition < c2.FKComposition THEN c1.FKComposition ELSE c2.FKComposition END as FKComposition
       ,CASE WHEN c1.FKComposition < c2.FKComposition THEN c2.FKComposition ELSE c1.FKComposition END as FKCompositionOfMatch
       ,c1.PartsCount
       ,COUNT(c2.FKComposition) / 2 as MatchedPartsCount
       ,COUNT(CASE WHEN c2.HighestPosition = c2.Position THEN c2.HighestPosition END) as MatchIncludesHighest
    FROM       
       cte c1
       INNER JOIN cte c2
       ON c1.FKComposition <> c2.FKComposition
       AND c1.FKPart = c2.FKPart
       AND c1.Quantity = c2.Quantity
       AND c1.PosRowNum = c2.PosRowNum
       AND c1.PosDif = c2.PosDif
    GROUP BY
       CASE WHEN c1.FKComposition < c2.FKComposition THEN c1.FKComposition ELSE c2.FKComposition END
       ,CASE WHEN c1.FKComposition < c2.FKComposition THEN c2.FKComposition ELSE c1.FKComposition END
       ,c1.PartsCount
       ,c2.PartsCount
    HAVING
       c1.PartsCount = c2.PartsCount
       AND (
          COUNT(c2.FKComposition) = (c1.PartsCount * 2) --there are 2 combinations 101 to 105 and 105 to 101 so must double the count
          OR (COUNT(c2.FKComposition) >= (c1.PartsCount * 2) - 2)
             AND COUNT(CASE WHEN c2.HighestPosition = c2.Position THEN c2.HighestPosition END) = 0
          )

您会注意到还有几个测试用例。最后 101 应该匹配 102 & 105 和 102 将匹配 105(和 101 通过代理)我简化为 1 个组合而不是重复,例如 101 匹配 102 和 102 匹配 101 你只会得到 101 匹配 102。

【讨论】:

    【解决方案2】:

    我写了下面的内容,它将为一个组合找到公园的相对位置......你可以在 where 子句中使用。抱歉,我不能再花时间帮助其他人了。

    SELECT STUFF((SELECT ',' + CAST(ISNULL(main.Position - sub.Position,0) AS VARCHAR(100)) AS ReletivePositions FROM
    (SELECT *, ROW_NUMBER ( ) OVER (ORDER BY FK_Part DESC)  as RowNumber
    FROM @PARTS P1
    WHERE FK_Composition = 101 /* << CHANGE THIS TO FK_Composition IN QUERY */ ) main
    LEFT JOIN (SELECT *, ROW_NUMBER ( ) OVER (ORDER BY FK_Part DESC)  as RowNumber
    FROM @PARTS WHERE FK_Composition =  101  /* << CHANGE THIS TO FK_Composition IN QUERY */ ) sub ON main.RowNumber + 1 = sub.RowNumber
    ORDER BY main.FK_Part DESC
    FOR XML PATH(''), TYPE 
    ).value('.', 'NVARCHAR(MAX)'),1,1,'') AS ReletivePositions
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多