SQL JOIN только к одной строке

У меня есть 2 таблицы данных о продажах, у которых нет общих ключей, только дата продажи и имя клиента. Я хочу присоединиться к ним так, чтобы для каждой строки из таблицы A было не более 1 совпадения из таблицы B или 0, если ничего не найдено. Проблема в том, что один и тот же клиент появляется дважды в один и тот же день. Итак, если у меня есть такие данные

Table A                             Table B

Customer | Date       | Receipt     Customer | Date       | Invoice
===============================     ===============================
John     | 2018-01-01 | A           John     | 2018-01-01 | C
John     | 2018-01-01 | B           John     | 2018-01-01 | D

Как мне это получить

Result

Customer | Date       | Receipt | Invoice
=========================================
John     | 2018-01-01 | A       | C
John     | 2018-01-01 | B       | D

Не имеет значения, совпадает ли квитанция A со счетом-фактурой C или D, если каждая из них сопряжена один раз. В настоящее время мой запрос объединяет все из них, AC, AD, BC, BD

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

  • AC и BD
  • Н.э. и до н.э.

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

Strawberry 17.07.2018 17:09

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

Daniel W. 17.07.2018 17:10

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

iceman2992 17.07.2018 17:14

«Мне нужен способ сделать это» - крик далеко из «Мне нужен способ сделать это в SQL». Пожалуйста, посмотрите мой ответ - такие вещи действительно действительно нужно делать на уровне отображения, а не в результате, возвращаемом SQL.

Kevin 17.07.2018 20:35
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
4
74
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Это неприятно, потому что вам нужно перечислить две таблицы, а затем либо join, либо агрегировать. Вот один из способов:

select customer, date, max(receipt) as receipt, max(invoice) as invoice
from ((select a.customer, a.date, a.receipt,
              (@rnr := if (@cd = concat_ws(';', customer, date), @rnr + 1,
                          if (@cd := concat_ws(';', customer, date), 1, 1)
                         )
              ) as seqnum
       from a cross join
            (select @rnr := 0, @cd := '') params
       order by a.customer, a.date
      ) union all
      (select b.customer, b.date, b.invoice,
              (@rni := if (@cd = concat_ws(';', customer, date), @rni + 1,
                          if (@cd := concat_ws(';', customer, date), 1, 1)
                         )
              ) as seqnum
       from b cross join
            (select @rni := 0, @cd := '') params
       order by a.customer, a.date
      )
     ) cd
group by customer, date, seqnum;

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

Kevin 17.07.2018 20:33

Почему бы просто не сделать отдельные после того, как вы соединили две таблицы, если вам нужны только отдельные записи?

SELECT DISTINCT a.Customer,
a.Date, 
a.Receipt, 
b.Invoice 
FROM Table_A a

JOIN Table_B b
ON a.Customer = b.Customer
AND a.Date = b.Date

Поскольку тогда будут дубликаты, например AD и BD, sql видит их как отдельные.

iceman2992 17.07.2018 17:55

Я дам ответ, который вам, вероятно, не понравится: этого нельзя делать в SQL. Это проблема презентации / отображения.

Выполняйте такую ​​работу на уровне, который отображает данные для пользователя, а не в серверной части SQL. Ищут ли они это на веб-странице? Затем попросите веб-страницу получить необработанные данные и отформатировать их по мере необходимости - пусть она помещает содержимое ежедневных квитанций или счетов-фактур каждого дня в отдельные блоки div. SQL отправляет электронное письмо с этими данными? Тогда не заставляйте его генерировать обычное текстовое электронное письмо - пусть он сгенерирует HTML и поместит данные в ячейки таблицы (чтобы вам не приходилось координировать строки между двумя наборами данных с возможно разными объемами данных).

Вы действительно не хотите играть в игру, пытаясь сделать вывод SQL красивым изнутри SQL. Потому что, честно говоря, код в принятом вами ответе может быть Работа правильно, но мне не хотелось бы пытаться поддерживать его на протяжении многих лет ...

Нет, это не проблема с презентацией / отображением, потому что это вставит данные в мою таблицу. Это извлекает данные из двух сторонних баз данных для вставки в мою, так что это проблема с данными.

iceman2992 18.07.2018 06:00

... нет, это не так. Нет причин, по которым вы не можете извлечь эти данные и сохранить их в правильной, нормализованной манере в своей базе данных (если это не имеет смысла, вы можете поискать в Google `` Нормализация SQL '' и получить много полезной информации о том, что Я говорю о.) И если никому не нужно видеть данных в этом формате, определенно нет веских причин для хранить это таким образом.

Kevin 18.07.2018 15:10

О да, есть, я ничего не могу сделать с их базами данных, я не контролирую сторонние системы. Я могу только обработать вывод. Моя база данных нормализована, их нет

iceman2992 19.07.2018 13:40

Другие вопросы по теме