MySQL столбец обновления, основанный на количестве от сложного соединения - PullRequest
0 голосов
/ 11 мая 2018

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

Table: search_data
------------------------------------------
id   partNumber    clei         searchDate
------------------------------------------
1    NT9X          null         2017-10-15 
2    NT9X          ENBYAAAAAA   2017-11-11 
3    null          ENBYAAAAAA   2017-11-12 
4    NT9X          null         2017-11-15 
5    NNTM          null         2017-11-15 
------------------------------------------

Table: analytics
--------------------------------------------
id   partNumber   clei          num_searches
--------------------------------------------
1    NT9X         ENBYAAAAAA    0
2    EFGH         EEEFFHI       0
3    NT9X         null          0
4    null         ENBYAAAAAA    0

Детали имеют 2 идентификатора: partNumber и CLEI

Так что это будет одна и та же часть:
- CLEI: ENBYAAAAAA
- Номер детали: NT9X

Поиск выполняется в таблице search_data , и пользователи могут выполнять поиск по partNumber, CLEI или обоим.Таким образом, для части, перечисленной выше, вы можете увидеть в search_data , что эта часть была найдена 4 раза (идентификаторы 1, 2, 3 и 4).

Мне нужно обновить столбец analytics таблицы *1022* num_searches с количеством поисков по этому номеру детали ИЛИ CLEI.

Таким образом, после обновления таблица analytics должна выглядеть следующим образом:

--------------------------------------------
id   partNumber   clei          num_searches
--------------------------------------------
1    NT9X         ENBYAAAAAA    4
2    EFGH         EEEFFHI       0
3    NT9X         null          4
4    null         ENBYAAAAAA    4

Я создал соединение, которое работает.

SELECT *
FROM analytics_data a
join search_data s
on 
case when a.partNumber is not null and a.partNumber != '' THEN a.partNumber = s.partNumber END
OR
case when a.clei is not null and a.clei != '' THEN a.clei = s.clei END

Я использовал операторы CASE, чтобы учесть тот факт, что в любой из таблиц могут присутствовать или не указываться номера partNumber и CLEI.Простое утверждение a.clei = s.clei, когда clei имеет значение NULL в аналитике, даст мне каждую строку с NULL clei в поисках, независимо от partNumber.

Эта дилемма затрудняет обновление.Я придумал это заявление об обновлении.Я не уверен, работает ли это или нет, потому что это не закончится.Я убил его через несколько минут, так как это неприемлемое время выполнения.

update analytics a
  set a.num_searches = 
  (
    select count(*) from search_data s where
      (case when a.partNumber is not null and a.partNumber != '' 
       THEN a.partNumber = s.partNumber END
    OR
       case when a.clei is not null and a.clei != '' THEN a.clei = 
        s.clei END)
  ) 

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

Есть идеи?

============================================================================ *

Дополнительные сведения для решения предлагаемого решения Ника.

Меня беспокоит то, что это множество итераций для этих частей.Деталь может иметь базовый код, такой как «NT9X», а также различные семейные коды (2 символа), а также другой набор функциональных кодов (еще 2 символа).

Так что мы могли бы иметь

NT9X
NT9XAB
NT9XBB
NT9XABAA
NT9XABBB

и так далее.Все это одна и та же общая часть, но с немного разными функциями.Есть также много комбинаций Part Number / CLEI.Один и тот же номер детали может иметь несколько кодов CLEI и наоборот.

В результате мы вынуждены выполнять множество запросов LIKE .Если я хотел получить все кавычки для части NT9X, у меня есть запрос вроде ...

SELECT * FROM part_quotes WHERE partNumber LIKE 'NT9X%';

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

Итак, в вашем сценарии мне нужно будет выполнить запрос LIKE к таблице part_numbers, чтобы получить все потенциальные совпадения деталей.Затем мне нужно было бы использовать предложение IN в соединениях таблиц для part_id.

Без этого я не знаю, будет ли это более или менее эффективным.

У меня много таблиц, в которых хранится информация о деталях.Таблицы как ...

vendor_quotes
internal_quotes
search_results
search_data
sales_history
repair_pricing
pricing
purchase_history
expenses

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

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

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

CREATE TABLE part_numbers 
    (id INT, `partNumber` VARCHAR(4), `clei` VARCHAR(10));
INSERT INTO part_numbers VALUES
    (1, 'NT9X', 'ENBYAAAAAA'),
    (2, 'EFGH', 'EEEFFHI');

SELECT * FROM part_numbers

id  partNumber  clei
1   NT9X        ENBYAAAAAA
2   EFGH        EEEFFHI
3   NNTM        EGFEDGF

И вы заменили поля partNumber и clei в search_data и analytics на поле part_id, которое ссылается на id в part_numbers, например, search_data будет выглядеть так:

id  part_id     searchDate
1   1           2017-10-15
2   1           2017-11-11
3   1           2017-11-12
4   1           2017-11-15
5   3           2017-11-15

Тогда ваш запрос на обновление будет просто:

UPDATE analytics a
   SET num_searches = (SELECT COUNT(s.id) FROM search_data s WHERE s.part_id = a.part_id)

This SQLFiddle показывает, как вы можете преобразовать свои таблицы, чтобы сделать вашу жизнь проще.

Если предположить, что вы не можете (или не хотите) изменять структуру таблиц, жизнь становится намного сложнее.С помощью этого запроса вы можете создать таблицу, в которой аналитика должна выглядеть ( SQLFiddle ):

SELECT a.id, a.partnumber, a.clei, COUNT(s.id) AS num_searches
FROM analytics a
LEFT JOIN analytics a2 
ON a.partnumber = a2.partnumber OR a.clei = a2.clei
LEFT JOIN search_data s
ON s.partnumber = a2.partnumber OR s.clei = a2.clei
WHERE a2.partnumber IS NOT NULL AND a2.clei IS NOT NULL
GROUP BY a.id

Вывод:

id  partnumber  clei        num_searches
1   NT9X        ENBYAAAAAA  4
2   EFGH        EEEFFHI     0
3   NT9X        (null)      4
4   (null)      ENBYAAAAAA  4

И поэтому запрос на обновление становится (обратите внимание, что нам пришлось JOIN подзапрос, поскольку мы не можем использовать подзапрос, содержащий таблицу обновлений в предложении SET) ( SQLFiddle ):

UPDATE analytics a4 JOIN (SELECT a.id AS id, COUNT(s.id) AS num_searches
FROM analytics a
LEFT JOIN analytics a2 
ON a.partnumber = a2.partnumber OR a.clei = a2.clei
LEFT JOIN search_data s
ON s.partnumber = a2.partnumber OR s.clei = a2.clei
WHERE a2.partnumber IS NOT NULL AND a2.clei IS NOT NULL
GROUP BY a.id) AS c
SET a4.num_searches = c.num_searches
WHERE a4.id = c.id

SELECT * FROM analytics

Вывод:

id  partnumber  clei        num_searches
1   NT9X        ENBYAAAAAA  4
2   EFGH        EEEFFHI     0
3   NT9X        (null)      4
4   (null)      ENBYAAAAAA  4
0 голосов
/ 11 мая 2018

Ваш код кажется слишком сложным, но я думаю, что он должен работать.Эта версия проще:

update analytics a
  set a.num_searches = (select count(*)
                        from search_data s
                        where a.partNumber = s.partNumber or
                              a.clei = s.clei
                       );

Ваши данные не имеют пробелов, поэтому нет смысла проверять их.

Но, как вы заметили, производительность довольно плохая.Вместо этого давайте сделаем это в двух частях.Если номера деталей совпадают, а затем clei не соответствует номеру детали:

update analytics a
  set a.num_searches = ((select count(*)
                         from search_data s
                         where a.partNumber <=> s.partNumber 
                        ) +
                        (select count(*)
                         from search_data s
                         where not a.partNumber <=> s.partNumber and
                               a.clei = s.clei
                        )
                       );

Эта версия должна иметь возможность использовать индексы для search_data(partNumber, clei) и search_data(clei, partNumber).

...