Группировка строк по сходству - PullRequest
0 голосов
/ 11 февраля 2020

Я работаю на SQL сервере.

У меня есть следующая таблица:

Для каждой BIGroup у меня есть несколько VarianceName. Для каждого VarianceName у меня есть несколько PartNumbers. Я сравниваю каждый номер детали с другими номерами в том же BIGroup и VarianceName и записываю количество различий между PartNumber1 и PartNumber2 в столбец Разница:

+---------+--------------+-------------+-------------+------------+-----------+
| BIGroup | VarianceName | PartNumber1 | PartNumber2 | Difference |  Cluster  |
+---------+--------------+-------------+-------------+------------+-----------+
| D934    | A            |    11426777 |    11426777 |          0 |           |
| D934    | A            |    11426777 |    11426781 |          0 |           |
| D934    | A            |    11426777 |    12542804 |          2 |           |
| D934    | A            |    11426777 |    12554759 |          4 |           |
| D934    | A            |    11426777 |    12564258 |          0 |           |
| D934    | A            |    11426781 |    11426777 |          0 |           |
| D934    | A            |    11426781 |    11426781 |          0 |           |
| D934    | A            |    11426781 |    12542804 |          5 |           |
| D934    | A            |    11426781 |    12554759 |          1 |           |
| D934    | A            |    11426781 |    12564258 |          0 |           |
| D934    | A            |    12542804 |    11426777 |          2 |           |
| D934    | A            |    12542804 |    11426781 |          5 |           |
| D934    | A            |    12542804 |    12542804 |          0 |           |
| D934    | A            |    12542804 |    12554759 |          0 |           |
| D934    | A            |    12542804 |    12564258 |          8 |           |
| D934    | A            |    12554759 |    11426777 |          4 |           |
| D934    | A            |    12554759 |    11426781 |          1 |           |
| D934    | A            |    12554759 |    12542804 |          0 |           |
| D934    | A            |    12554759 |    12554759 |          0 |           |
| D934    | A            |    12554759 |    12564258 |          9 |           |
| D934    | A            |    12564258 |    11426777 |          0 |           |
| D934    | A            |    12564258 |    11426781 |          0 |           |
| D934    | A            |    12564258 |    12542804 |          8 |           |
| D934    | A            |    12564258 |    12554759 |          9 |           |
| D934    | A            |    12564258 |    12564258 |          0 |           |
| D934    | AA           |    11438878 |    11438878 |          0 |           |
| D934    | AB           |    11438924 |    11438924 |          0 |           |
| D934    | AC           |    12556213 |    12556213 |          0 |           |
| D934    | AC           |    12556213 |    12556214 |          5 |           |
| D934    | AC           |    12556214 |    12556213 |          5 |           |
| D934    | AC           |    12556214 |    12556214 |          0 |           |
| D955    | A            |    75346846 |    75346846 |          0 |           |
| ...     | ...          |    ...      |    ...      |          0 |           |
+---------+--------------+-------------+-------------+------------+-----------+

например: для D934, для VarianceName A, PartNumbers 11426777, 11426781 и 12564258 идентичны, поскольку между 0: 11426777 и 11426781, 11426781 и 12564258, а также 12564258 и 11426777. * и 10064 *

ex: для D934, для номеров VarianceName A, PartNumbers 12542804 и 12554759 идентичны, потому что D934 0 различий между: 12542804 и 12554759.

Моя цель - идентифицировать все группы идентичных номеров PartNumbers в одной и той же BIGroup и VarianceName. Чтобы пометить эти группы, я буду использовать столбец с именем Кластер .

Итак, 11426777, 11426781 и 12564258 будут принадлежать кластеру D934-A-C1.

Так что 12542804 и 12554759 будут принадлежать кластеру D934-A-C2.

Каким должен быть запрос / хранимая процедура для обновите столбец кластера , чтобы получить следующий результат:

+---------+--------------+-------------+-------------+------------+-----------+
| BIGroup | VarianceName | PartNumber1 | PartNumber2 | Difference |  Cluster  |
+---------+--------------+-------------+-------------+------------+-----------+
| D934    | A            |    11426777 |    11426777 |          0 | D934-A-C1 |
| D934    | A            |    11426777 |    11426781 |          0 | D934-A-C1 |
| D934    | A            |    11426777 |    12542804 |          2 |           |
| D934    | A            |    11426777 |    12554759 |          4 |           |
| D934    | A            |    11426777 |    12564258 |          0 | D934-A-C1 |
| D934    | A            |    11426781 |    11426777 |          0 | D934-A-C1 |
| D934    | A            |    11426781 |    11426781 |          0 | D934-A-C1 |
| D934    | A            |    11426781 |    12542804 |          5 |           |
| D934    | A            |    11426781 |    12554759 |          1 |           |
| D934    | A            |    11426781 |    12564258 |          0 | D934-A-C1 |
| D934    | A            |    12542804 |    11426777 |          2 |           |
| D934    | A            |    12542804 |    11426781 |          5 |           |
| D934    | A            |    12542804 |    12542804 |          0 | D934-A-C2 |
| D934    | A            |    12542804 |    12554759 |          0 | D934-A-C2 |
| D934    | A            |    12542804 |    12564258 |          8 |           |
| D934    | A            |    12554759 |    11426777 |          4 |           |
| D934    | A            |    12554759 |    11426781 |          1 |           |
| D934    | A            |    12554759 |    12542804 |          0 | D934-A-C2 |
| D934    | A            |    12554759 |    12554759 |          0 | D934-A-C2 |
| D934    | A            |    12554759 |    12564258 |          9 |           |
| D934    | A            |    12564258 |    11426777 |          0 | D934-A-C1 |
| D934    | A            |    12564258 |    11426781 |          0 | D934-A-C1 |
| D934    | A            |    12564258 |    12542804 |          8 |           |
| D934    | A            |    12564258 |    12554759 |          9 |           |
| D934    | A            |    12564258 |    12564258 |          0 | D934-A-C1 |

и т. д. для другого VarianceName

| D934    | AA           |    11438878 |    11438878 |          0 | D934-AA-C1  
| D934    | AB           |    11438924 |    11438924 |          0 | D934-AB-C1
| D934    | AC           |    12556213 |    12556213 |          0 | D934-AC-C1
| D934    | AC           |    12556213 |    12556214 |          5 |
| D934    | AC           |    12556214 |    12556213 |          5 |
| D934    | AC           |    12556214 |    12556214 |          0 | D934-AC-C1

и т. д. для другого BiGroup

| D955    | A            |    75346846 |    75346846 |          0 | D955-A-C1
| ...     | ...          |    ...      |    ...      |        ... |
+---------+--------------+-------------+-------------+------------+-----------+

Столбец следует оставить равным NULL, если разница> 0

Вот сценарий для получения данных в виде cte:

with t1 as
( 
select 'D934'  as BIGroup  ,'A'    as VarianceName  ,   11426777 as PartNumber1,   11426777 as PartNumber2,         0 as Difference,  null as Cluster        
union select 'D934'    ,'A'            ,   11426777 ,   11426781 ,         0 , null
union select 'D934'    ,'A'            ,   11426777 ,   12542804 ,         2 , null
union select 'D934'    ,'A'            ,   11426777 ,   12554759 ,         4 , null
union select 'D934'    ,'A'            ,   11426777 ,   12564258 ,         0 , null
union select 'D934'    ,'A'            ,   11426781 ,   11426777 ,         0 , null
union select 'D934'    ,'A'            ,   11426781 ,   11426781 ,         0 , null
union select 'D934'    ,'A'            ,   11426781 ,   12542804 ,         5 , null
union select 'D934'    ,'A'            ,   11426781 ,   12554759 ,         1 , null
union select 'D934'    ,'A'            ,   11426781 ,   12564258 ,         0 , null
union select 'D934'    ,'A'            ,   12542804 ,   11426777 ,         2 , null
union select 'D934'    ,'A'            ,   12542804 ,   11426781 ,         5 , null
union select 'D934'    ,'A'            ,   12542804 ,   12542804 ,         0 , null
union select 'D934'    ,'A'            ,   12542804 ,   12554759 ,         0 , null
union select 'D934'    ,'A'            ,   12542804 ,   12564258 ,         8 , null
union select 'D934'    ,'A'            ,   12554759 ,   11426777 ,         4 , null
union select 'D934'    ,'A'            ,   12554759 ,   11426781 ,         1 , null
union select 'D934'    ,'A'            ,   12554759 ,   12542804 ,         0 , null
union select 'D934'    ,'A'            ,   12554759 ,   12554759 ,         0 , null
union select 'D934'    ,'A'            ,   12554759 ,   12564258 ,         9 , null
union select 'D934'    ,'A'            ,   12564258 ,   11426777 ,         0 , null
union select 'D934'    ,'A'            ,   12564258 ,   11426781 ,         0 , null
union select 'D934'    ,'A'            ,   12564258 ,   12542804 ,         8 , null
union select 'D934'    ,'A'            ,   12564258 ,   12554759 ,         9 , null
union select 'D934'    ,'A'            ,   12564258 ,   12564258 ,         0 , null
union select 'D934'    ,'AA'           ,   11438878 ,   11438878 ,         0 , null
union select 'D934'    ,'AB'           ,   11438924 ,   11438924 ,         0 , null
union select 'D934'    ,'AC'           ,   12556213 ,   12556213 ,         0 , null
union select 'D934'    ,'AC'           ,   12556213 ,   12556214 ,         5 , null
union select 'D934'    ,'AC'           ,   12556214 ,   12556213 ,         5 , null
union select 'D934'    ,'AC'           ,   12556214 ,   12556214 ,         0 , null
union select 'D955'    ,'A'            ,   75346846 ,   75346846 ,         0 , null
)

Редактировать: Чтобы лучше понять проблему, я нарисовал 5 номеров по каталогу D934 A, их ссылки и два кластера.

Интересующие нас ссылки - черные (потому что это означает, что есть 0 различий между номерами деталей).

Оранжевые ссылки представляют разницу> 0. PartNumbers.

После рисования ссылок мы можем выделить 2 кластера, которые я нарисовал красными кружками.

enter image description here

Ответы [ 3 ]

1 голос
/ 11 февраля 2020

Попробуйте это:

;WITH cte_p(BIGroup, VarianceName, PartNumber1, PartNumber2)
AS
(
    SELECT BIGroup, VarianceName, PartNumber1, PartNumber2
    FROM t1 
    WHERE [Difference]=0
),
cte_c(BIGroup, VarianceName, PartNumber1, PartNumber2, COrder)
AS
(
    SELECT p1.BIGroup, p1.VarianceName, p1.PartNumber1, p1.PartNumber2,
        DENSE_RANK() OVER (PARTITION BY p1.BIGroup, p1.VarianceName ORDER BY p1.PartNumber1) AS COrder
    FROM cte_p p1
    WHERE NOT EXISTS(SELECT 1 FROM cte_p p2
        WHERE p2.PartNumber1<>p2.PartNumber2
        AND p1.BIGroup=p2.BIGroup
        AND p1.VarianceName=p2.VarianceName
        AND p1.PartNumber1=p2.PartNumber2)
)

SELECT t.*,t.BIGroup+'-'+t.VarianceName+'-C'+CAST(c.COrder AS nvarchar(20))
FROM t1 t
INNER JOIN cte_c c
ON t.BIGroup=c.BIGroup
AND t.VarianceName=c.VarianceName
AND t.PartNumber1=c.PartNumber1;
1 голос
/ 12 февраля 2020

Мне удалось решить эту проблему с помощью хранимой процедуры:

DECLARE @BiGroup                    [nvarchar](30);
DECLARE @VarianceName               [nvarchar](30);
DECLARE @NewBiGroup                 [nvarchar](30);
DECLARE @NewVarianceName            [nvarchar](30);
DECLARE @PartNumber                 [nvarchar](30);
DECLARE @ClusterName                [nvarchar](30);
DECLARE @IncrementClusterName       [nvarchar](30);

set @BiGroup = 'first_BiGroup';
set @VarianceName = 'first_VarianceName';
set @IncrementClusterName = 1;
set @ClusterName = null;

-- Declare cursor
DECLARE cur CURSOR READ_ONLY FOR
Select [PartNumber1] FROM t1
order by [BIGroup] ,[VarianceName] ,[PartNumber1];

--clean cluster column
update t1 set [Cluster]=null;

OPEN cur
FETCH NEXT FROM cur INTO @PartNumber

-- Loop on every PartNumber
WHILE @@FETCH_STATUS = 0
BEGIN

  --set NewBiGroup and NewPartNumber
  set @NewBiGroup = (select Top(1) [BIGroup] from t1 where partnumber1 = @PartNumber);
  set @NewVarianceName = (select Top(1) [VarianceName] from t1 where partnumber1 = @PartNumber);

  --check if we are still in the same BIGroup and Variance, otherwise, reset the cluster increment
  if @NewBiGroup <> @BiGroup or @NewVarianceName <> @VarianceName 
  BEGIN
    set @IncrementClusterName = 1;
  END

  --get the clusterName of this partNumber, if it exists
  set @ClusterName = (select Top(1) [Cluster] from t1 where partnumber2 = @PartNumber and [Cluster] is not null);

  --if ClusterName is NULL, put a clustername and then increment the @IncrementClusterName, 
  --otherwise set the cluster to @ClusterName
  if @ClusterName is null
  BEGIN
    update t1 set [Cluster] = @NewBiGroup+'-'+@NewVarianceName+'-'+@IncrementClusterName
    where partnumber1 = @PartNumber  
    and Difference= 0 ;

    set @IncrementClusterName = @IncrementClusterName +1;
  END
  else
  BEGIN
    update t1 set [Cluster] = @NewBiGroup+'-'+@NewVarianceName+'-'+@ClusterName
    where partnumber1 = @PartNumber  
    and Difference= 0 ;
  END

  -- setting the BiGroup and VarianceName
  set @BiGroup = @NewBiGroup;
  set @VarianceName = @NewVarianceName;

 FETCH NEXT FROM cur INTO @PartNumber
END

CLOSE cur
DEALLOCATE cur

Алгоритм хранимой процедуры работает следующим образом:

  • Для каждого PartNumber с разницей = 0
    • Если BiGroup или VarianceName изменился
      • Я сбрасываю @clusterIncrement на 1
    • Если он еще не часть Cluster
      • Я установил его Cluster на @clusterIncrement
      • @clusterIncrement = @clusterIncrement +1
    • Если он уже является частью Cluster
      • Я установил его Cluster на существующий Cluster
1 голос
/ 11 февраля 2020

Вы можете использовать DENSE_RANK для генерации числа для каждого кластера.

Когда этот ранг затем объединяется с BIGroup & VarianceName, вы получите код кластера.

Сложность состоит в том, чтобы найти что-то общее между этими кластерами.

В приведенном ниже запросе используется хитрость, в которой он вычисляет минимальную и сумму PartNumber2 для разностей 0.
И использует их для DENSE_RANK.

;WITH CTE1 AS
(
  SELECT *
  , P2Min0 = MIN(CASE WHEN Difference = 0 THEN PartNumber2 END)
            OVER (PARTITION BY BIGroup, VarianceName, PartNumber1)
  , P2Sum0 = SUM(CASE WHEN Difference = 0 THEN PartNumber2 END)
            OVER (PARTITION BY BIGroup, VarianceName, PartNumber1)
  FROM t1
)
, CTE2 AS
(
SELECT *
  , Rnk = DENSE_RANK()
          OVER (PARTITION BY BIGroup, VarianceName ORDER BY P2Min0, P2Sum0)
  FROM CTE1
  WHERE Difference = 0
)
UPDATE CTE2
SET Cluster = CONCAT(BIGroup, '-', VarianceName, '-', Rnk)

Тест по db <> fiddle здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...