Помогите с MySQL Join - PullRequest
       2

Помогите с MySQL Join

1 голос
/ 01 ноября 2010

У меня есть две таблицы: Продажи (ISBN, Sale_Time, [Поля данных продажи]) и Affiliate_Sales (ISBN, Партнерская_продажа-время, [Поля данных филиала]).

Я бы хотел запросить все не истекшие продажи (<24 часа) и неистекшие Affiliate_Sales (<72 часа) для заданного набора ISBN. Я хотел бы, чтобы строка возвращалась для данного номера ISBN, даже если есть не истекшие продажи, но нет неиспользованных Affiliate_Sales, И наоборот (но ничего не должно быть возвращено, когда их нет). Я считаю, что это называется ПОЛНОЕ СОЕДИНЕНИЕ. </p>

Не думаю, что UNION будет работать здесь, потому что таблицы различаются по всем полям, кроме ISBN.

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

Обновление: Как вы можете видеть из моих комментариев ниже, я пытаюсь получить все данные о продажах и все данные Affiliate_Sales, а не только ISBN и время.

Обновление 2: вот как будет выглядеть результат

ISBN    Sale_DateTime   [Sale Fields…]  Affiliate_Sale_DateTime [Affiliate Sale Fields…]
1   11/6/2010 11:28    All the sale Fields  11/6/2010 0:28     All the affiliate Sale fields
2   NULL               NULLs                11/6/2010 0:28     All the affiliate Sale fields
3   11/6/2010 11:28    All the sale Fields  NULL               NULLs

Если для получения этого требуется больше обработки на стороне SQL, чем просто выполнение двух базовых запросов SELECT, как предлагает длинный запрос Бруно, может быть, я должен просто сделать два?

Ответы [ 4 ]

0 голосов
/ 08 ноября 2010

Определение требований

Существуют некоторые противоречивые и недостаточно определенные требования, которые вы указали в вопросе и комментариях, но я полагаю, что это одна из причин, по которой вы его задаете.

Позвольте мне перечислить их для вас

  1. вы хотите перечислить номера ISBN, которые являются элементами любого из двух определенных подмножеств из двух таблиц (продажи с истекшим сроком и партнерские продажи с истекшим сроком действия)
  2. вы хотите отобразить дополнительные столбцы из обеих таблиц, а не только ISBN
  3. вам не нужны значения NULL

(я использую подмножество терминов, потому что на концептуальном уровне не важно указывать условия для ваших не истекших подмножеств)

Вот несколько значений

  • если вы хотите перечислить ISBNs + поля из обеих таблиц для записи, которая находится только в одном из подмножеств, тогда вы должны иметь NULL для другой стороны; это противоречит # 3

  • является ли ISBN уникальным в обеих таблицах? Если да, игнорируйте этот пункт: если ISBN не уникален, то вам нужно указать, как объединить подмножества двух таблиц, в противном случае вы получите каждую строку по одной для каждой из другой

Если номера ISBN уникальны

Теперь, если ваши ISBN уникальны в обеих таблицах, тогда ответ Бруно, кажется, указывает в правильном направлении (хотя он не прошел полный SQL-запрос, он кажется слишком сложным).

Способы реализации НАРУЖНЫХ СОЕДИНЕНИЙ в mysql:

  • UNION of LEFT JOIN и RIGHT JOIN (не UNION ALL, а UNION, который будет принимать отдельные строки; он также соответствует формальному определению)
  • UNION ALL из LEFT JOIN и RIGHT EXCLUSION JOIN (UNION ALL может быть значительно быстрее, особенно на больших наборах результатов); эта опция имеет прямо симметричный эквивалент (UNION ALL of RIGHT JOIN и LEFT EXCLUSION JOIN)
  • UNION ALL из INNER JOIN и LEFT EXCLUSION JOIN и RIGHT EXCLUSION JOIN (INNER JOIN может быть значительно быстрее, чем LEFT JOIN, если селективность высока и , если в соединениях исключения могут использоваться индексы)

Если некоторые из используемых здесь терминов неясны, см. Примеры в Common MySQL Queries .

Если номера ISBN не уникальны

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

EDIT После уточнений вы можете попробовать это решение

SELECT * FROM Sales a LEFT JOIN Affiliate_Sales b ON a.ISBN=b.ISBN
WHERE TIMESTAMPDIFF(HOUR, Sale_DateTime, Now()) < 24 
      AND (TIMESTAMPDIFF(HOUR, Affiliate_Sale_DateTime, Now()) < 72 
      OR Affiliate_Sale_DateTime IS NULL)
UNION ALL
SELECT * FROM Sales a RIGHT JOIN Affiliate_Sales b ON a.ISBN=b.ISBN
WHERE TIMESTAMPDIFF(HOUR, Affiliate_Sale_DateTime, Now()) < 72 
      AND Sale_DateTime IS NULL; 

Если вы хотите, чтобы оно было короче, вам нужно создать представления. Кроме того, посмотрите на предоставленную ссылку, она неплохая.

0 голосов
/ 02 ноября 2010

Если у вас всегда будет ISBN в таблице продаж, вы можете ПОЛНОСТЬЮ ПРИСОЕДИНИТЬСЯ и получить результаты, которые вы ищете.В противном случае вам нужно будет присоединиться слева.

select *
from Sales s
FULL OUTER JOIN Affiliate_Sales asa on asa.ISBN = s.ISBN
where DATEDIFF(hh, s.Sale_Time, GETDATE()) < 24
OR DATEDIFF(hh, asa.Sale_Time, GETDATE()) < 72

РЕДАКТИРОВАТЬ - Попробуйте описать выше или следующее:

SELECT ISBN, Sale_Time 
FROM Sales s 
where DATEDIFF(hh, s.Sale_Time, GETDATE()) < 24
UNION ALL
SELECT ISBN, Affiliate_Sale_Time AS Sale_Time 
FROM Affiliate_Sales asa 
where DATEDIFF(hh, asa.Sale_Time, GETDATE()) < 72

Если вы хотите больше полей, вам нужно будет назвать ихв частности, если таблицы не структурированы одинаково.ПОЛНОЕ СОЕДИНЕНИЕ даст вам все результаты.Мой предыдущий ответ включал ВНУТРЕННЕЕ СОЕДИНЕНИЕ, которое ограничило бы ваши результаты.

РЕДАКТИРОВАТЬ - Пример выбора полей, которые не совпадают:

select itemid, null, path, null, name
from Catalog

union all

select itemid, dsid, null, username, null
from DataSource
0 голосов
/ 07 ноября 2010

У вас действительно есть проблема FULL OUTER JOIN, но, к сожалению, в настоящее время она не поддерживается MySQL.

К счастью для нас, мы можем эмулировать FULL OUTER JOIN между таблицами A и B с помощью:

  • a СЛЕДУЮЩЕЕ ВНЕШНЕЕ СОЕДИНЕНИЕ из таблицы A в таблицу B для перехвата строк в A, которых нет в B, и совпадения строк между A и B
  • a ПРАВИЛЬНОЕ ИСКЛЮЧЕНИЕ ПРИСОЕДИНЯЙТЕСЬ от таблицы B к таблице A для отловастроки в B, которых нет в A

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

  1. Сначала нам нужно извлечьISBN, которые соответствуют критериям времени истечения
  2. Затем мы можем получить информацию из обеих таблиц для ранее выбранных ISBN

Вот пример сценария для проверки нашего запроса:

CREATE TABLE sales ( 
   isbn INT NOT NULL
  ,sale_time TIMESTAMP NOT NULL
  ,sale_value VARCHAR(100)
  ,PRIMARY KEY (isbn)
);
CREATE TABLE affiliate_sales ( 
   isbn INT NOT NULL
  ,sale_time TIMESTAMP NOT NULL
  ,affiliate_sale_value VARCHAR(100)
  ,PRIMARY KEY (isbn)
);

INSERT INTO sales (isbn,sale_time,sale_value) VALUES (1,TIMESTAMPADD(HOUR,-30,NOW()),'expired_sale');
INSERT INTO sales (isbn,sale_time,sale_value) VALUES (2,TIMESTAMPADD(HOUR,-34,NOW()),'expired_sale');
INSERT INTO sales (isbn,sale_time,sale_value) VALUES (3,TIMESTAMPADD(HOUR,-23,NOW()),'unexpired_sale');
INSERT INTO sales (isbn,sale_time,sale_value) VALUES (4,TIMESTAMPADD(HOUR,-12,NOW()),'unexpired_sale');
INSERT INTO sales (isbn,sale_time,sale_value) VALUES (5,TIMESTAMPADD(HOUR,-12,NOW()),'unexpired_sale_only');

INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (1,TIMESTAMPADD(HOUR,-74,NOW()),'expired_affiliate_sale');
INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (2,TIMESTAMPADD(HOUR,-54,NOW()),'unexpired_affiliate_sale');
INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (3,TIMESTAMPADD(HOUR,-80,NOW()),'expired_affiliate_sale');
INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (4,TIMESTAMPADD(HOUR,-12,NOW()),'unexpired_affiliate_sale');
INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (6,TIMESTAMPADD(HOUR,-44,NOW()),'unexpired_affiliate_sale_only');

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

SELECT unexpired_sal.isbn
, sal.sale_time, sal.sale_value
, afs.sale_time affiliate_sale_time, afs.affiliate_sale_value
FROM (
SELECT sal.isbn
FROM (
SELECT isbn FROM sales
WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 24
) sal
LEFT JOIN (
SELECT isbn FROM affiliate_sales
WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 72
) afs
ON afs.isbn = sal.isbn
UNION ALL
SELECT afs.isbn
FROM (
SELECT isbn FROM sales
WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 24
) sal
RIGHT JOIN (
SELECT isbn FROM affiliate_sales
WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 72
) afs
ON afs.isbn = sal.isbn
WHERE sal.isbn IS NULL
) unexpired_sal
LEFT JOIN (
SELECT * FROM sales
WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 24
) sal
ON sal.isbn = unexpired_sal.isbn
LEFT JOIN (
SELECT * FROM affiliate_sales
WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 72
) afs
ON afs.isbn = unexpired_sal.isbn
;

Вы получите следующий вывод:

+------+---------------------+---------------------+---------------------+-------------------------------+
| isbn | sale_time           | sale_value          | affiliate_sale_time | affiliate_sale_value          |
+------+---------------------+---------------------+---------------------+-------------------------------+
|    3 | 2010-11-06 11:28:08 | unexpired_sale      |                NULL | NULL                          |
|    4 | 2010-11-06 22:28:08 | unexpired_sale      | 2010-11-06 22:28:08 | unexpired_affiliate_sale      |
|    5 | 2010-11-06 22:28:08 | unexpired_sale_only |                NULL | NULL                          |
|    2 |                NULL | NULL                | 2010-11-05 04:28:08 | unexpired_affiliate_sale      |
|    6 |                NULL | NULL                | 2010-11-05 14:28:08 | unexpired_affiliate_sale_only |
+------+---------------------+---------------------+---------------------+-------------------------------+
5 rows in set (0.00 sec)
0 голосов
/ 02 ноября 2010

UNION должен работать, если вы используете «AS» для определения имени возвращаемых полей, чтобы они совпадали.Например:

SELECT ISBN, Sale_Time FROM Sales
UNION ALL
SELECT ISBN, Affiliate_Sale_Time AS Sale_Time FROM Affiliate_Sales
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...