Как я могу выполнить это обновление?

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

У меня есть таблица A, которая содержит столбцы PK и Code. У меня есть таблица B, которая содержит столбцы PK, Data, Code и FK. Количество повторяющихся записей с одинаковыми данными и кодом в таблице B равно количеству повторяющихся записей с одинаковым кодом в таблице A.

Я хочу обновить FK в таблице B, чтобы каждая повторяющаяся запись (те же данные и тот же код) указывала на уникальный PK в таблице A на основе совпадающего кода в таблице A и таблице B.

Пример:

 |Table A
| PK         |         Code| 
|:-----------|------------:|
| 1          |        v665 |
| 2          |        v665 |
| 3          |        v665 |   
| 4          |        v998 |
| 5          |         y69 |
| 6          |         y69 |

Table B
| PK | Data        | Code | FK |
|:---|------------:|:----:|---:|
| 1  |   some info | v665 |    | <- should be updated to Table A PK 1
| 2  |   some info | v665 |    | <- should be updated to Table A PK 2
| 3  |   some info | v665 |    | <- should be updated to Table A PK 3
| 4  |   important | v665 |    | <- should be updated to Table A PK 1
| 5  |   important | v665 |    | <- should be updated to Table A PK 2
| 6  |   important | v665 |    | <- should be updated to Table A PK 3
| 7  |  more stuff | v665 |    | <- should be updated to Table A PK 1
| 8  |  more stuff | v665 |    | <- should be updated to Table A PK 2
| 9  |  more stuff | v665 |    | <- should be updated to Table A PK 3
| 10 |   some data | v998 |    | <- should be updated to Table A PK 4
| 11 |   some more | v998 |    | <- should be updated to Table A PK 4
  

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

Ответ №1:

Один из способов сделать это — использовать функцию row_number window для создания уникального значения, которое можно использовать для объединения:

 update b
   set b.fk = a.pk
  from (select b.*,
               row_number() over (partition by b.code, b.data order by b.pk) as rn
          from TableB b) b
  join (select a.*,
               row_number() over (partition by a.code order by a.pk) as rn
          from TableA a) a
    on a.code = b.code
   and a.rn = b.rn
  

Комментарии:

1. Вау! Хороший запрос. Однако мне трудно понять это. Не могли бы вы немного объяснить, как это работает?

2. Ключом к пониманию инструкции update является понимание функции row_number window. Вы можете прочитать об этом здесь: msdn.microsoft.com/en-us/library/ms186734.aspx . Как только это станет немного понятнее, выполните 2 подзапроса по отдельности и посмотрите, как rn генерируются значения. Вы заметите, что для каждой логической группировки ( code в таблице A и (code, data) в таблице B — см. partition by Предложения) row_number каждая строка в этих группах будет иметь уникальный номер. Этот уникальный номер для каждой логической группы затем используется как часть условия соединения для правильного сопоставления строк.