2016-12-02 3 views
0

Рассмотрим следующий многие-ко-многим таблице:самоприсоединение таблицы и сопоставления нескольких строк

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 

Цель состоит в том, чтобы найти композиции, которые в значительной степени такой же, как в определенной композиции по comparisson. «Довольно много» смысл:

  1. сравниваемых композиция состоит из одних и тех же частей, что и оригинал, кроме части с самым высоким положением
  2. Все части должны быть на одних и тех же относительно позиции (позиции [-3, -2, -1,0] допускается при сравнении композиции с позициями [-1,0,1,2])
  3. Каждое происхождение части должно иметь такое же количество
  4. сравниваемая композиция не имеет больше частей, чем оригинал

Идя по этим правилам, состав 102 в значительной степени же, как 101.

Конечно, есть более интересно было с моим вопросом: Наша Entity Framework позволяет только использование простых запросах ВЫБОРА и, мы должны поддерживать как базы данных SQL Server, так и Access «Базы данных». Запрос должен поддерживать обе системы, а временные таблицы и циклы - это не выход.

Я работал с разными базами данных некоторое время, но я не помню, что мне когда-либо приходилось сопоставлять несколько значений из нескольких строк в самосоединении, как это раньше. Тем не менее, я считаю разумным предположить, что должен быть быть простым способом достичь этого. Здесь?

Вопрос с бонусом: я собираюсь запросить данные, которые мне нужны в отдельных частях нашего приложения .NET, и пусть Linq делает свою магию, но есть опасения, что компьютеры некоторых клиентов могут не очень хорошо обрабатывать слишком много встроенной памяти данные. Мы говорим о данных, возможно, до миллиона строк, в зависимости от баз данных клиентов. Является ли это серьезной проблемой?

Edit - В соответствии с просьбой в комментариях, вот некоторые контрпримеры с композициями, которые не должны соответствовать по сравнению с составом 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  | 
+1

Возможно, вы должны добавить намного больше тестовых примеров, чтобы объяснить несколько других нюансов. Например, они должны иметь одинаковое количество деталей? Например. что если 103 имеет 6 частей и первые 3 соответствуют первым 3 из 101, это будет близкое совпадение? – Matt

+0

Я думаю, 1) говорит, что они должны иметь одни и те же части (кроме самого высокого положения). Но я согласен, что больше примеров будет очень полезно - по крайней мере, контрпример из чего-то, что не должно совпадать. Также вы когда-нибудь получите набор позиций, которые не являются последовательными, например. (1,2,2,3) или (1,3,6578)? И нужно ли соответствовать самой высокой части? –

+0

@Matt Да, они имеют одинаковое количество деталей. И количество позиций, и количество каждой позиции должны совпадать. –

ответ

0

вот версия SQL-сервера. Это НЕ работало бы в ms-доступе и, честно говоря, все подзапросы и производные таблицы и вещи, которые были бы необходимы для этого в msa-доступе, не интересуют меня в письменной форме. Но это должно дать вам представление о том, какой-то логике и т.д.

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.

0

I написал ниже, что найдет относительные позиции парков для композиции ... вы можете использовать там, где есть предложение. Извините, я не могу тратить больше времени, чтобы помочь с остальными.

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 
Смежные вопросы