MySQL 根据复杂连接的计数更新列

标签 mysql sql join count sql-update

我正在努力构建一个具有相当复杂的数据库模式的报告。我有下表(为简洁起见,进行了简化)。

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 次(id 1、2、3 和 4)。

我需要使用该部件号 CLEI 的搜索次数来更新分析表的num_searches列。

因此,更新后,分析表应如下所示:

--------------------------------------------
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。当 clei 在分析中为 NULL 时,一个简单的 a.clei = s.clei 语句将在搜索中为我提供带有 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)
  ) 

我不知道从这里该去哪里。这似乎是一项简单的任务,但我厌倦了把头撞在 table 上。

有什么想法吗?

================================================== =========================

解决 Nick 提议的解决方案的更多详细信息。

我担心的是这些部分需要进行多次迭代。零件可以有一个基本代码,如“NT9X”,加上各种系列代码(2 个字符),再加上其他各种特征代码(另外 2 个字符)。

所以我们可以有

NT9X
NT9XAB
NT9XBB
NT9XABAA
NT9XABBB

等等。所有部件都是相同的通用部件,但功能略有不同。还有很多零件号/CLEI 组合。同一部件号可以有多个 CLEI 代码,反之亦然。

因此,我们被迫执行大量LIKE查询。如果我想获取 NT9X 部分的所有报价,我有一个查询,例如...

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

对于 1 部分来说效果很好。但对于像现在这样的情况,我有一个包含 6000 多个零件的列表,并且需要来自十几个不同表的数据来生成报告,这是不可能通过单个查询来完成的。

因此,对于您的场景,我必须对part_numbers表执行LIKE查询才能获取所有潜在的部分匹配。然后,我必须在part_id 的表连接中使用IN 子句。

如果没有进行测试,我不知道它的效率是否会更高或更低。

我有很多存储零件信息的表。表格如...

vendor_quotes
internal_quotes
search_results
search_data
sales_history
repair_pricing
pricing
purchase_history
expenses

还有更多。尝试构建一个必须对如此多的表和聚合数据进行通配符搜索的报告是相当令人头疼的。我肯定需要一种更好的方法来做到这一点,并将在不久的将来测试您的解决方案。

最佳答案

这是数据库正确规范化的经典论点。如果您有一个像这样的表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

并且您将 search_dataanalytics 中的 partNumberclei 字段替换为字段 part_id 引用了 part_numbers 中的 id,例如 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)

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

关于MySQL 根据复杂连接的计数更新列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50287767/

相关文章:

java - java中如何找出sql结果集中的变量类型?

sql - 如何连接/连接 SQLite 中分组列中的字符串?

SQL:限制链接到每个连接行的行

mysql - phpmyadmin 上的 docker compose 不正确

java - 从java在mysql中从root创建其他用户

SQL 查询仅查找 2 列中的唯一字符串

c# - Entity Framework 5为空

php - CakePHP - 从 find() 方法中的 JOIN 中排除模型

mysql - 如何将本地 .SQL 文件加载到 MySQL 中?

mysql - 您不能在 FROM 子句中指定要更新的目标表 'A'