【问题标题】:MySQL update column based on count from complex joinMySQL 根据复杂连接的计数更新列
【发布时间】:2018-10-21 14:27:00
【问题描述】:

我正在使用相当复杂的数据库架构构建报表。我有以下表格(为简洁起见进行了简化)。

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

所以这将是相同的部分:
- 克莱:ENBYAAAAAA
- 部件号:NT9X

搜索进入 search_data 表,用户可以通过 partNumber、CLEI 或两者进行搜索。因此对于上面列出的部分,您可以在 search_data 中看到该部分已被搜索了 4 次(ids 1、2、3 和 4)。

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

所以更新后,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 的事实。当 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)
  ) 

我不知道从这里去哪里。这似乎是一项简单的任务,但我已经厌倦了用头撞桌子。

有什么想法吗?

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

解决 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

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

【问题讨论】:

  • 我没有完全得到你的结果。 “4”从何而来?我认为结果应该是 4、0、3、2。
  • 4 是因为 PN: NT9XCLEI: ENBYAAAAAA 是同一部分。对其中任何一个的任何搜索都是双向的。 ENBYAAAAAA 是搜索 NT9X,搜索 NT9X 是搜索 ENBYAAAAAA。

标签: mysql sql join count sql-update


【解决方案1】:

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

【讨论】:

  • 感谢详细的 cmets。我同意它应该更好,并计划在未来几个月内重新设计数据库。你的想法是我正在考虑的一个。但这很复杂。有关更多详细信息,请参阅我对上述问题的附录。
【解决方案2】:

您的代码似乎太复杂了,但我认为它应该可以工作。这个版本比较简单:

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) 上的索引。

【讨论】:

  • 这似乎没有给 OPs 想要的结果SQLFiddle
  • 实际上,我已经在我的开发系统上运行了它,并且一些抽查似乎表明它正在运行。第二个索引似乎也让它变得非常快。我已经有了 (partNumber, celi) 索引。我没有意识到使用相反的 (clei, partNumber) 会有所作为,但确实如此。
  • @scott80109 。 . .您不接受答案有什么原因吗?
  • 进一步测试表明这在大多数情况下都有效,但如果 partNumber 为 NULL 则无效。不幸的是,这个解决方案并不能解决所提出的问题。
  • 你可以在这里看到小提琴 - sqlfiddle.com/#!9/b8775/1/0v - 它表明缺少的 partNumber 没有给出正确的 4 计数。
猜你喜欢
  • 1970-01-01
  • 2016-11-16
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多