Самосвязывание в таблицах, SQL, Python и JavaScript

Начнем с таблицы данных employees с самоссылками:

id  name                 manager_id
1   Djan Seriy Anaplian
2   Fal 'Ngeestra
3   Turminder Xuss       1           --->  Djan Seriy Anaplian
4   Jase                 2           --->  Fal 'Ngeestra
Войдите в полноэкранный режим Выход из полноэкранного режима

Как мы можем получить другую запись?

Листы

Как и многие другие вопросы в Excel, Numbers, Calc или Sheets, давайте решим их, добавив столбец с формулой INDEX и MATCH:

# 1. find row number of the matching record
=match(C2, A:A, 0)

# 2. get value from the other record
=index(B:B, match(C2, A:A, 0))

# 3. handle errors
=iferror(index(B:B, match(C2, A:A, 0)), "")
Войти в полноэкранный режим Выход из полноэкранного режима

Вы можете опробовать этот пример в Sheets:

SQL

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

select
  e.name employee,
  m.name manager
from employees e
left join employees m on e.manager_id = m.id
Войти в полноэкранный режим Выйти из полноэкранного режима

Попробуйте в SQL Fiddle:

Python

Чтобы представить «нормальную форму» наших данных в Python, давайте выберем словарь:

employees = {
    1: {'name': 'Djan Seriy Anaplian'},
    2: {'name': 'Fal 'Ngeestra'},
    3: {'name': 'Turminder Xuss', 'manager_id': 1},
    4: {'name': 'Jase', 'manager_id': 2},
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы хотим изменить его на список вложенных словарей, заменив каждый указатель manager_id на живой объект manager, чтобы дать себе наибольшую свободу для исследования. Используя императивный процедурный стиль кода с оператором моржа := и dict.pop(), это может выглядеть следующим образом:

for em in employees.values():
    if manager_id := em.pop('manager_id', None):
        em['manager'] = employees[manager_id]

employees = list(employees.values())
employees[0]['short'] = 'Anaplian'
employees[1]['short'] = 'Fal'
Вход в полноэкранный режим Выйти из полноэкранного режима

Этот пример живет на Repl.it. Будет ли он работать для более глубокой иерархии управления? Сломается ли он для циклической структуры?

Дайте мне знать, если вы хотите увидеть другие стили кода в Python, функциональные, как JS ниже, или FRP, как Sheets выше (с Pandas).

JavaScript / TypeScript

Мы можем начать с точно такого же объекта employees, как в примере Python, но на этот раз мы выбираем более дружественный для команды подход, вдохновленный функциональным стилем программирования, который позволяет избежать мутации и побочных эффектов, поскольку вложенные объекты могут быть использованы в других частях проекта. Мы также хотим избежать слишком большого количества уровней вложенности, чтобы сохранить простоту, поэтому мы заменим manager_id необязательной неизменяемой строкой managerName:

const employeesWithManager = Object.values(employees)
  .map(({name, manager_id}) => ({
    name,
    ...(manager_id && {
      managerName: employees[manager_id].name
    }),
  }))
Войти в полноэкранный режим Выход из полноэкранного режима

Вы можете поиграть с версией TypeScript на TS Playground или запустить пример JavaScript прямо в консоли браузера:

Заметили ли вы, как мы можем использовать синтаксис распространения в объектном литерале ({...expr}) с более сложным выражением, а не просто с именем переменной? Можете ли вы рефакторить код, чтобы использовать явную переменную в этом месте? Какая версия более читабельна для вас и для ваших коллег по проекту?


👋 Привет, я Питер Хозак, он же Aprillion. Есть ли у вас какие-либо последующие или похожие вопросы? Давайте обсудим их в комментариях ниже или в Twitter.

Оцените статью
devanswers.ru
Добавить комментарий