C join: c strings — join() or implode() in C

Объединение таблиц с помощью операторов Join и Keep ‒ Qlik Sense для Windows

Объединение — операция объединения двух таблиц в одну. Записи результирующей таблицы представляют собой комбинации записей в исходных таблицах. При этом две такие записи, составляющие одну комбинацию в результирующей таблице, как правило, имеют общее значение одного или нескольких общих полей. Такое объединение называется естественным. В программе Qlik Sense объединение может выполняться в скрипте, создавая логическую таблицу.

Таблицы, которые находятся в скрипте, можно объединять. Логика Qlik Sense будет распознавать не отдельные таблицы, а результаты объединения, которые будут представлены в одной внутренней таблице. В некоторых случаях это требуется, однако существуют недостатки:

  • Загруженные таблицы часто становятся больше, и программа Qlik Sense работает медленнее.
  • Некоторая информация может быть потеряна: частота (количество записей) в исходной таблице может быть больше недоступна.

Функция Keep, которая позволяет уменьшить одну или обе таблицы до пересечения данных таблиц перед сохранением таблиц в программу Qlik Sense, предназначена для уменьшения количества случаев, когда необходимо использовать явные объединения.

Примечание об информацииВ данном руководстве термин «объединение» обычно используется для объединений, выполненных до создания внутренних таблиц. Однако ассоциация, выполненная после создания внутренних таблиц, по сути, также является объединением.

Объединения внутри оператора SQL SELECT

При использовании некоторых драйверов ODBC можно выполнять объединение внутри оператора SELECT. Это практически эквивалентно созданию объединения с помощью префикса Join.

Однако большинство драйверов ODBC не позволяют сделать полное внешнее объединение (двунаправленное). Они позволяют сделать только левостороннее или правостороннее внешнее объединение. Левостороннее (правостороннее) внешнее объединение включает только сочетания, в которых в левой (правой) таблице существует ключ объединения. Полное внешнее объединение включает все сочетания. Программа Qlik Sense автоматически создает полное внешнее объединение.

Более того, создание объединений в операторах SELECT значительно сложнее, чем создание объединений в программе Qlik Sense.

Пример:  

SELECT DISTINCTROW

[Order Details].ProductID, [Order Details].

UnitPrice, Orders.OrderID, Orders.OrderDate, Orders.CustomerID

FROM Orders

RIGHT JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID;

Этот оператор SELECT позволяет объединить таблицу, содержащую заказы несуществующей компании, и таблицу, содержащую сведения о заказах. Это правостороннее внешнее объединение, то есть будут включены все записи OrderDetails и записи со значением OrderID, которое отсутствует в таблице Orders. Однако заказы, содержащиеся в таблице Orders, но не содержащиеся в OrderDetails, не будут включены.

Join

Самым простым способом создания объединения является использование префикса Join в скрипте, который позволяет объединять внутреннюю таблицу с другой именованной таблицей или последней созданной таблицей. Объединение будет внешним и позволит создать все возможные сочетания значений из двух таблиц.

Пример:  

LOAD a, b, c from table1.csv;

join LOAD a, d from table2.csv;

Результирующая внутренняя таблица имеет поля a, b, c и d. Количество записей различается в зависимости от значений полей этих двух таблиц.

Примечание об информацииИмена объединяемых полей должны совпадать. Количество объединяемых полей может быть любым. Обычно в таблицах должно быть одно или несколько общих полей. При отсутствии общих полей будет рассматриваться декартово произведение таблиц. В принципе все поля могут быть общими, однако обычно в этом нет смысла. Пока имя ранее загруженной таблицы не будет указано в операторе Join, префиксом Join будет использоваться последняя созданная таблица. Поэтому порядок двух операторов не является произвольным.

Для получения дополнительной информации см. Join.

Keep

Явный префикс Join в скрипте загрузки данных выполняет полное объединение двух таблиц. В результате получается одна таблица. Во многих случаях такие объединения приводят к созданию очень больших таблиц. Одной из основных функций программы Qlik Sense является способность к связыванию таблиц вместо их объединения, что позволяет сократить использование памяти, повысить скорость обработки и гибкость. Функция keep предназначена для сокращения числа случаев необходимого использования явных объединений.

Префикс Keep между двумя операторами LOAD или SELECT приводит к уменьшению одной или обеих таблиц до пересечения их данных перед сохранением таблиц в программе Qlik Sense. Перед префиксом Keep следует задать одно из ключевых слов: Inner, Left или Right. Выборка записей из таблицы осуществляется так же, как и при соответствующем объединении. Однако две таблицы не объединяются и сохраняются в программе Qlik Sense в виде двух отдельных именованных таблиц.

Для получения дополнительной информации см. Keep.

Inner

Перед префиксами Join и Keep в скрипте загрузки данных можно использовать префикс Inner.

При использовании этого префикса перед префиксом Join объединение двух таблиц будет внутренним. Полученная таблица содержит только сочетания из двух таблиц, включающие полный набор данных с обеих сторон.

Если этот префикс используется перед Keep, он указывает, что две таблицы следует уменьшить до области взаимного пересечения, прежде чем они смогут быть сохранены в программе Qlik Sense.

Пример:  

В этих таблицах используются исходные таблицы Table1 и Table2:

Table 1
AB
1aa
2cc
3ee
Table2
AC
1xx
4yy

Inner Join

Сначала выполняется Inner Join в отношении таблиц, в результате чего образуется таблица VTable, содержащая только одну строку, только одну запись, существующую в обеих таблицах, с данными из обеих таблиц.

VTable:

SELECT * from Table1;

inner join SELECT * from Table2;

VTable
ABC
1aaxx

Inner Keep

Если вместо этого выполняется Inner Keep, таблиц все равно будет две. Две таблицы связаны посредством общего поля A.

VTab1:

SELECT * from Table1;

VTab2:

NotToTranslate»>inner keep SELECT * from Table2;

VTab1
AB
1aa
VTab2
AC
1xx

Для получения дополнительной информации см. Inner.

Left

Перед префиксами Join и Keep в скрипте загрузки данных можно использовать префикс left.

При использовании этого префикса перед префиксом Join объединение двух таблиц будет левосторонним. Полученная таблица содержит только сочетания из двух таблиц, включающие полный набор данных из первой таблицы.

Если этот префикс используется перед префиксом Keep, он указывает, что вторую таблицу следует уменьшить до области взаимного пересечения с первой таблицей перед сохранением в программе Qlik Sense.

Пример:  

В этих таблицах используются исходные таблицы Table1 и Table2:

Table1
AB
1aa
2cc
3ee
NotToTranslate»/>

Table2
AC
1xx
4yy

Сначала выполняется Left Join в отношении таблиц, в результате чего образуется таблица VTable, содержащая все строки из таблицы Table1, совмещенные с полями из совпадающих строк в таблице Table2.

VTable:

SELECT * from Table1;

left join SELECT * from Table2;

NotToTranslate»/>

VTable
ABC
1aaxx
2cc
3ee

Если вместо этого выполняется Left Keep, таблиц все равно будет две. Две таблицы связаны посредством общего поля A.

VTab1:

SELECT * from Table1;

VTab2:

left keep SELECT * from Table2;

NotToTranslate»/>

VTab1
AB
1aa
2cc
3ee
VTab2
AC
1xx

Для получения дополнительной информации см. Left.

Right

Перед префиксами Join и Keep в скрипте загрузки данных можно использовать префикс right.

При использовании этого префикса перед префиксом Join объединение двух таблиц будет правосторонним. Полученная таблица содержит только сочетания из двух таблиц, включающие полный набор данных из второй таблицы.

Если этот префикс используется перед префиксом Keep, он указывает, что первую таблицу следует уменьшить до области взаимного пересечения со второй таблицей перед сохранением в программе Qlik Sense.

Пример:  

В этих таблицах используются исходные таблицы Table1 и Table2:

Table1
AB
1aa
2cc
3ee
NotToTranslate»/>

Table2
AC
1xx
4yy

Сначала выполняется Right Join в отношении таблиц, в результате чего образуется таблица VTable, содержащая все строки из таблицы Table2, совмещенные с полями из совпадающих строк в таблице Table1.

VTable:

SELECT * from Table1;

right join SELECT * from Table2;

NotToTranslate»/>

VTable
ABC
1aaxx
4yy

Если вместо этого выполняется Right Keep, таблиц все равно будет две. Две таблицы связаны посредством общего поля A.

VTab1:

SELECT * from Table1;

VTab2:

right keep SELECT * from Table2;

NotToTranslate»/>

VTab1
AB
1aa
VTab2
AC
1xx
4yy

Для получения дополнительной информации см. Right.

Как собрать данные из нескольких связанных таблиц с помощью Join

Реляционная модель данных подразумевает отдельное хранение и
возможность независимой обработки данных для каждой сущности.

Вместе с тем, часто возникает потребность собрать данные из нескольких связанных таблиц.

Как правило, сущности (таблицы) связаны друг с другом
внешними связями по принципу (primary key — foreign key).

Связи могут быть типа «1 к 1» или «1
ко многим»
(с вариантами «1 к 0 или 1», «1 к
0 или более»
, «1 к 2» и пр).
Связь «многие-ко-многим»
в реляционной модели обеспечивается с помощью дополнительной таблицы связей
(другие названия: Link-таблица, Bridge-таблица, xref-таблица).

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

  • внутренним соединением (INNER JOIN). При этом:
    • если для описания связи между наборами данных используются корреляционные подзапросы, то такой INNER JOIN называют CROSS APPLY
    • если условие соединения отсутствует, то такой INNER JOIN называют “декартовым произведением” (CROSS JOIN, CARTESIAN PRODUCT)
  • внешним соединением (OUTER JOIN). Разновидности — LEFT JOIN, RIGHT JOIN, FULL JOIN
    • если для описания связи между наборами данных используются корреляционные подзапросы, то такой OUTER JOIN называют OUTER APPLY

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

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

Пример логической модели данных:

Обратите внимание на характер данных в наших таблицах.

У некоторых спортсменов нет категории, клуба или тренера (возможно, они
неизвестны).
Встречаются
спортсмены, которых ведёт несколько тренеров.

Про одни сущности есть чуть больше информации чем про другие.

Знакомство с данными.

In [1]:

 
use tempdb
go
--содержимое таблиц:
select * from dbo.SwimmingClub 
select * from dbo.Swimmer
select * from dbo.Category 
(3 rows affected) 
(7 rows affected) 
(3 rows affected) 

Out [1]:

Пример #1. Найти всех спортсменов из клуба Янтарь, имеющих II спортивный разряд.

Используя старую нотацию:

In [2]:

 
use tempdb
go
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, c.[Name] Category
from dbo.SwimmingClub sc, dbo.Swimmer s, dbo.Category c
where sc.[Name] like N'%Янтарь%' 
      and sc.SwimmingClubID = s.SwimmingClubID
      and s.CategoryID     = c.CategoryID
      and c.[Name]         = N'II'
 (1 row affected) 

Out [2]:

В этой форме записи WHERE-часть перегружена
условиями
. Часть из них относятся к логической модели данных (у. 2 и 3), часть – к
логике текущей задачи (у. 1 и 4).

В сложных запросах WHERE-часть может стать просто огромной!

Используя новую нотацию:

In [3]:

 
use tempdb
go
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc. City, c.[Name] Category
from dbo.SwimmingClub sc
inner join dbo.Swimmer s  on s.SwimmingClubID = sc.SwimmingClubID
inner join dbo.Category c on s.CategoryID     = c.CategoryID
where sc.[Name] like N'%Янтарь%' and c.[Name] = N'II'
 (1 row affected) 

Out [3]:

Преимуществом этой формы записи
является “разгрузка” WHERE-части от условий, определенных логической моделью данных, при этом четко
видно какое из условий используется для реализации связи между какими
таблицами.

В сложных запросах новая форма записи позволяет добиться существенно лучшей читаемости кода (а, как увидим позже, еще и лучшей готовности кода к рефакторингу).

Используя CROSS JOIN:

In [4]:

 
use tempdb
go
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, c.[Name] Category
from dbo.SwimmingClub sc
cross join dbo.Swimmer s
cross join dbo.Category c
where sc.[Name] like N'%Янтарь%' 
      and sc. SwimmingClubID = s.SwimmingClubID
      and s.CategoryID     = c.CategoryID
      and c.[Name]         = N'II'
 (1 row affected) 

Out [4]:

Обратите внимание на то, как запрос с CROSS JOIN похож на вариант решения в старой нотации!
На самом деле, ничего удивительного, т. к. логически они выражают один и тот же подход к решению задачи: “все источники данных — в FROM, все условия — в WHERE. При отсутствии условий каждая таблица декартово перемножается с каждой”.

Вообще, вариантов решения задачи много. Но, как можно догадаться, не все они оптимальны;).

Например, порой начинающие программисты для решения первой задачи создают что-то вроде этого:

In [5]:

 
use tempdb
go
declare @ClubId     int,
        @ClubCity   nvarchar(30), 
        @ClubName   nvarchar(100),
        @CategoryId int
set @ClubId = (
   select SwimmingClubId from dbo.SwimmingClub where [Name] like N'%Янтарь%'
)
set @ClubCity = (
   select City from dbo. SwimmingClub where [Name] like N'%Янтарь%'
)
set @ClubName = (
   select [Name] from dbo.SwimmingClub where [Name] like N'%Янтарь%'
)
set @CategoryId = (
   select CategoryId from dbo.Category where [Name] = N'II'
)
select SwimmerID, FirstName, LastName, YearOfBirth, Gender, 
       @ClubName Club, @ClubCity City, N'II' Category
from dbo.Swimmer 
where SwimmingClubID = @ClubId and CategoryId = @CategoryId
 (1 row affected) 

Out [5]:

Идея за этим кодом такова.

Чтобы найти всех спортсменов из клуба Янтарь, имеющих II спортивный разряд, нужно:

  1. dbo.SwimmingClub

найти код клуба Янтарь (значение внешнего ключа SwimmingClubId)

2. dbo.Category

найти код категории, указывающей на II разряд (значение внешнего ключа CategoryId)

3. dbo.Swimmer

зная эти два значения, найти соответствующих пловцов

Приведенный выше алгоритм “напрашивается” сам собой. Именно поэтому разработчики, далекие от SQL, пишут такие решения.

Недостатком этого подхода являются:

  • длинный код (объявление переменных + 5 инструкций SELECT)
  • худшая производительность (пять селектов явно медленнее одного)
  • неизолированность от конкурирующих транзакций (пока мы рассчитываем значения переменных, данные в любой из таблиц могут быть изменены кем-то другим)
  • если есть несколько клубов со словом “Янтарь” в названии, любой из трех первых селектов упадет.

Пример #2. Вывести спортсменов из клуба Янтарь с теми же атрибутами что и выше, но без требования иметь II спортивный разряд.

Используя старую нотацию:

In [6]:

 
use tempdb
go
--это код с багом! в случае если у спортсмена нет разряда, запись о нем не выводится
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, c.[Name] Category
from dbo.SwimmingClub sc, dbo.Swimmer s, dbo.Category c
where sc.[Name] like N'%Янтарь%' 
      and sc. SwimmingClubID = s.SwimmingClubID
      and s.CategoryID     = c.CategoryID      
--подправленный код (один из вариантов)
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, 
       (select c.[Name] from dbo.Category c where c.CategoryID = s.CategoryID) Category
from dbo.SwimmingClub sc, dbo.Swimmer s
where sc.[Name] like N'%Янтарь%' 
      and sc.SwimmingClubID = s.SwimmingClubID         
(2 rows affected) 
(3 rows affected) 

Out [6]:

Интуитивно напрашивающееся решение
адаптировать старый код под новые требования удалением соответствующего условия
не работает!

В старой нотации нужно существенно менять сам код при незначительных изменениях в требованиях.

Используя новую нотацию:

In [7]:

use tempdb
go
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, c.[Name] Category
from dbo.SwimmingClub sc
inner join dbo. Swimmer s on s.SwimmingClubID = sc.SwimmingClubID
left join dbo.Category c on s.CategoryID     = c.CategoryID
where sc.[Name] like N'%Янтарь%' 
 (3 rows affected) 

Out [7]:

В отличии от старой, после удаления уже ненужного требования, в новой
нотации нужно лишь поменять слово
inner на left.

Вот и все!

Вариант решения задачи с outer apply:

In [8]:

 use tempdb
go
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, c.[Name] Category
from dbo.SwimmingClub sc
inner join dbo.Swimmer s  on s.SwimmingClubID = sc.SwimmingClubID
outer apply (select [Name] from dbo.Category c where c.CategoryID = s.CategoryId) c 
where sc.[Name] like N'%Янтарь%' 
 
(3 rows affected) 

Out [8]:

Несмотря на запись запроса, похожую на вариант с LEFT JOIN, этот способ не
оптимален из-за имеющегося корреляционного подзапроса
.
Последний приводит к тому, что выполнение идет по принципу rowbyrow вместо setbased. Логически, мы
выполняем корреляционный подзапрос с внешним параметром s.CategoryId столько раз, сколько строчек в таблице dbo.Swimmer.

Корреляционные запросы существенно ухудшают производительность!

Вариант решения задачи с пользовательской скалярной функцией:

In [9]:

 use tempdb
go
create or alter function dbo.fn_GetCategoryName(@CategoryID int) 
returns nvarchar
as
begin
  return (select [Name] from dbo.Category where CategoryId = @CategoryID)
end
go
select s.SwimmerID, s.FirstName, s.LastName, s.YearOfBirth, s.Gender, 
       sc.[Name] Club, sc.City, dbo.fn_GetCategoryName(s.CategoryId) Category
from dbo.SwimmingClub sc
inner join dbo.Swimmer s  on s.SwimmingClubID = sc.SwimmingClubID
where sc.[Name] like N'%Янтарь%' 
(3 rows affected) 

Out [9]:

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

Вместе с тем, это решение в условиях баз данных, скорее всего, еще хуже предыдущего:

  • корреляционный подзапрос никуда не делся, он лишь мигрировал в тело функции
  • в ходе выполнения запроса функция будет вызвана множество раз, что негативно влияет на производительность (из-за особенностей работы СУБД и интерпретатора языка SQL)
  • для решения одной конкретной задачи понадобилось создать дополнительный постоянный объект БД – пользовательскую скалярную функцию.

Если пользоваться таким подходом постоянно, то скоро БД будет завалена множеством непонятных программных объектов!

Вывод.

В рассмотренных примерах победителем стал запрос, созданный в новой нотации без использования корреляционных подзапросов. Он максимально читабельный, легко меняется в случае изменения требований, производительный и не требует создания дополнительных объектов в БД.

Автор материала – Тимофей Гавриленко, преподаватель Тренинг центра ISsoft.

Образование: окончил с отличием математический факультет Гомельского Государственного Университета им. Франциска Скорины.

Microsoft Certified Professional (70-464, 70-465).

Работа: c 2011 года работает в компании ISsoft (ETL/BI Developer, Release Manager, Data Analyst/Architect, SQL Training Manager), на протяжении 10 лет до этого выступал как Sysadmin, DBA, Software Engineer.

В свободное время ведет бесплатные образовательные курсы для детей и взрослых, желающих повысить свой уровень компьютерной грамотности и переквалифицироваться в IT-специалиста.

Присоединяйтесь к команде — C+C

Чтобы просмотреть наши текущие вакансии Нажмите здесь

Почему C+C?

C+C состоит из добрых и заботливых людей, увлеченных работой, которую они выполняют для наших клиентов и вместе с ними. Люди, которые любят решать проблемы, выполнять сжатые сроки и реализовывать инновационные проекты, которые защищают людей и окружающую среду. Люди, которые проектируют, планируют, разрабатывают стратегии, консультируют, производят, трансформируют, исследуют и внедряют. Люди, которые будут приветствовать вас такими, какие вы есть, и примут то, что вы привносите в нашу культуру.

Работа и культура C+C формируются нашими общими ценностями. Мы работаем, чтобы воплощать эти ценности в каждой встрече, электронной почте, звонке, текстовом сообщении, счастливом часе и в любом другом случае, когда мы взаимодействуем с нашими клиентами и коллегами. И когда мы терпим неудачу, мы признаем это, учимся на этом и пробуем снова.

Честное и открытое общение: Мы говорим искренне и даем вдумчивую обратную связь, чтобы помочь друг другу и нашим клиентам стать лучше. Руководство прозрачно и доступно.

Целостность: Мы ставим наших клиентов и коллег на первое место, даже когда это трудно, даже когда нам это не нужно. Этические принципы определяют все, что мы делаем, как внутри компании, так и за ее пределами.

Сотрудничество: Мы верим, что хорошие идеи могут прийти откуда угодно. Наш процесс нормализует прямую обратную связь и включает в себя вклад коллег с разным опытом, подходами и областями знаний, чтобы сделать нашу работу лучше.

Разнообразие, равноправие и инклюзивность: Мы создаем инклюзивное рабочее место, которое отмечает богатое разнообразие как наших сотрудников, так и клиентов. Мы делаем это, практикуя межкультурную компетентность, выстраивая подлинные и поддерживающие отношения, а также распространяя истории из сообществ, в которых мы живем и работаем.

Креативность и изобретательность:   Мы изучаем свое ремесло и бесстрашно задаемся вопросом «почему», чтобы понять, как что-то делалось в прошлом, чтобы улучшить будущие результаты для наших клиентов.

Что еще?

C+C предлагает отличный социальный пакет, который включает в себя проездной билет на общественный транспорт и превращает ваш день рождения в праздник, конкурентоспособную оплату и все (в основном) полезные закуски, которые вы только можете пожелать. Наша команда достаточно велика, чтобы вы могли получить поддержку в своих проектах, но все же достаточно мала, чтобы действовать быстро. Мы можем — и будем — следовать нашему творчеству в инновационной работе для наших клиентов без разрозненных команд, которые могут утомить вас в более крупном агентстве.  

C+C — работодатель, предоставляющий равные возможности, и мы ценим многообразие в нашей компании. Мы придерживаемся принципа равных возможностей трудоустройства и создаем для сотрудников рабочую среду, свободную от дискриминации и домогательств.

Мы не допускаем дискриминации по признаку расы, цвета кожи, религии или убеждений, национального, социального или этнического происхождения, пола (включая беременность), возраста, физической, умственной или сенсорной инвалидности, ВИЧ-статуса, сексуальной ориентации, гендерной идентичности и/или самовыражение, статус в браке, гражданском союзе или домашнем партнерстве, прошлая или настоящая военная служба, история болезни семьи или генетическая информация, семейный или родительский статус или любой другой статус, защищенный законами или правилами в местах, где мы работаем.

C+C не потерпит дискриминации или домогательств по любому из этих признаков. Мы стремимся к видимому и невидимому разнообразию в нашей команде, и цветным рекомендуется подавать заявки.

Посмотрите, как Мел Си присоединилась к Blossoms на сцене Гластонбери для обложки Spice Girls

Поиск

Sporty Spice поднялся на сцену, чтобы исполнить «Spice Up Your Life» с группой из Стокпорта

Blossoms ПРЕДОСТАВЛЕНО: Парри Томас

Мел Си присоединилась к Blossoms на сцене сегодня днем ​​(24 июня), чтобы исполнить кавер на песню Spice Girls «Spice Up Your Life». Посмотрите кадры ниже.

Группа Stockport выступала на The Other Stage, когда к ним присоединилась Spice Girl: «Поскольку технически это 50-летие, мы подумали, что сделаем что-то немного особенное», — сказал фронтмен Том Огден. «Есть ли у нас в доме фанаты Spice Girls? Хорошо, пожалуйста, поприветствуйте на сцене Мелани Си, также известную как Sporty Spice».

Когда Мел Си присоединилась к группе на сцене, Огден спросил ее: «Правильно, мы собираемся это сделать? Простите мою попытку движений, но у вас получилось. Посмотрите кадры ниже из маловероятного сотрудничества.

Реклама

Цветы только что принесли Мел Си на ❤️ pic.twitter.com/NLa1Ci20dX

— Том Копли (@tomcopley) 24 июня 2022 г.

К

Blossoms только что присоединился особый гость, чтобы сыграть в Spice Up Your Life.

Это #Гластонбери Мэла Си, и мы просто живем в нем. pic.twitter.com/m1xsLGPfEy

— Марк Сэвидж (@mrdiscopop) 24 июня 2022 г.