【问题标题】:Smarter way to SQL query [closed]更智能的 SQL 查询方法 [关闭]
【发布时间】:2022-01-21 23:18:11
【问题描述】:

我正在使用 2 个查询(如果需要更多)来检查属于特定用户组织的总用户(按返回的行数),方法是检查目标 ID 是否存在于gene_chain 中,并想知道我是否有任何方法可以查询一次,而不是我目前在做什么?

每个用户都有一个上线,并且可以与我们的目标 ID 不同。这些表没有任何特定列供我们直接参考查找答案,只有gene_chain具有生成链的特定顺序,以便我们查找哪些用户在其gene_chain中有目标ID

user_id upline_id gene_chain
100002 100001 0,100001
100003 100002 0,100001,100002
100004 100002 0,100001,100002
100005 100003 0,100001,100002,100003
100006 100004 0,100001,100002,100004
100007 100006 0,100001,100002,100004,100006
100008 100007 0,100001,100002,100004,100006,100007
100009 100005 0,100001,100002,100003,100005
100010 100005 0,100001,100002,100003,100005
100011 100008 0,100001,100002,100004,100006,100007,100008

查询 #1:100002 的组织下有多少用户

SELECT 
  DP.team.parent_id AS Upline, 
  DP.users.id AS UserID, 
  DP.users.nickname AS Username, 
  DP.users.email AS Email, 
  DP.users.country AS Country, 
  DP.team.gene_chain, DP.team.gene_num
FROM (DP.team INNER JOIN DP.users ON DP.team.user_id = DP.users.id)
WHERE DP.team.gene_chain LIKE '%100002%';

查询 #2:100005 的组织下有多少用户

SELECT 
  DP.team.parent_id AS Upline,
  DP.users.id AS UserID, 
  DP.users.nickname AS Username, 
  DP.users.email AS Email, 
  DP.users.country AS Country, 
  DP.team.gene_chain, DP.team.gene_num
FROM (DP.team INNER JOIN DP.users ON DP.team.user_id = DP.users.id)
WHERE DP.team.gene_chain LIKE '%100005%';

查询 3:这将返回 100002 和 100005 组织下的总用户数。这就是为什么我仍然坚持单独进行查询并好奇是否有更智能或更快的方法来实现这一点

SELECT 
DP.team.parent_id AS Upline, 
DP.users.id AS UserID, 
DP.users.nickname AS Username, 
DP.users.email AS Email, 
DP.users.country AS Country, 
DP.team.gene_chain, 
DP.team.gene_num
FROM (DP.team INNER JOIN DP.users ON DP.team.user_id = DP.users.id)
WHERE DP.team.gene_chain LIKE '%100002%' OR DP.team.gene_chain LIKE '%100005%'
ORDER BY DP.team.gene_chain ASC;

【问题讨论】:

  • 您尝试过什么解决问题的方法?你被困在哪里了?使用OR 连接这两个条件是否有帮助?
  • 我从每个查询返回的行中找到我的答案,并且执行 OR 会混淆 ID,因此目前我正在单独进行查询。只是想知道是否有更智能、更快的方法来实现这一点。
  • 扩展您的 WHERE 以包含所需的基因链,然后查看 GROUP BY。如果没有样本数据,则需要做更多的工作来弄清楚您需要什么。
  • 请以文本形式为您的问题添加所有说明。不要使用屏幕截图获取重要信息
  • 小心。看起来您的逻辑可能有问题,即使在每个单独的查询中也是如此。 gene_chain LIKE '%100002%'; 也将匹配 110000210000211000022 等。如果这些类型的值是不可能的,你可能没问题。更安全的方法是在模式中包含分隔符,这可能需要稍作更改:gene_chain LIKE '%,100002,%'; 您可以在“逗号分隔列表”上查找 SQL 文章以获取更多详细信息。提供对链标识符的保证限制的描述,以允许审查。

标签: mysql sql


【解决方案1】:

这里有一些东西可以尝试(但未经测试)。 它展示了可用于在一个查询中处理多种模式的方法。

仅适用于 MySQL 5.7+ 并仅计算发现的每个基因模式。

如果您想要每个团队的计数,请调整 GROUP BYSELECT list

SELECT p.pattern
     , COUNT(*) AS n
  FROM DP.team JOIN DP.users ON DP.team.user_id = DP.users.id
  JOIN (
         SELECT '%,100002,%' AS pattern UNION ALL
         SELECT '%,100005,%'
       ) AS p
    ON CONCAT('%,', DP.team.gene_chain, ',%') LIKE p.pattern
 GROUP BY p.pattern
 ORDER BY p.pattern
;

我们真的不需要为此与用户一起加入:

SELECT p.pattern
     , COUNT(*) AS n
  FROM DP.team
  JOIN (
         SELECT '%,100002,%' AS pattern UNION ALL
         SELECT '%,100005,%'
       ) AS p
    ON CONCAT('%,', DP.team.gene_chain, ',%') LIKE p.pattern
 GROUP BY p.pattern
 ORDER BY p.pattern
;

结果:

+------------+---+
| pattern    | n |
+------------+---+
| %,100002,% | 9 |
| %,100005,% | 2 |
+------------+---+

第一个查询需要 MySQL 8.0+ 或 MariaDB 10.2.2+。 第二个查询支持这些和旧版本。

-- This returns all the matching rows (to maintain your current result)
-- Plus adds `n` per row indicating the count of rows per matching pattern (chain)
-- I've included a better pattern be sure the right chains are identified.
WITH patterns (pattern) AS (
       SELECT '%,100002,%' UNION ALL
       SELECT '%,100005,%'
     )
SELECT DP.team.parent_id AS Upline
     , DP.users.id AS UserID
     , DP.users.nickname AS Username
     , DP.users.email AS Email
     , DP.users.country AS Country
     , DP.team.gene_chain
     , DP.team.gene_num
     , p.pattern
     , COUNT(*) OVER (PARTITION BY p.pattern) AS n
  FROM DP.team JOIN DP.users ON DP.team.user_id = DP.users.id
  JOIN patterns AS p
    ON CONCAT('%,', DP.team.gene_chain, ',%') LIKE p.pattern
 ORDER BY p.pattern
;

结果:

+--------+--------+----------+-------+---------+---------------------------------------------+----------+------------+---+
| Upline | UserID | Username | Email | Country | gene_chain                                  | gene_num | pattern    | n |
+--------+--------+----------+-------+---------+---------------------------------------------+----------+------------+---+
| 100005 | 100009 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100002,% | 9 |
| 100004 | 100006 |     NULL |  NULL |    NULL | 0,100001,100002,100004                      |     NULL | %,100002,% | 9 |
| 100002 | 100003 |     NULL |  NULL |    NULL | 0,100001,100002                             |     NULL | %,100002,% | 9 |
| 100005 | 100010 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100002,% | 9 |
| 100007 | 100008 |     NULL |  NULL |    NULL | 0,100001,100002,100004,100006,100007        |     NULL | %,100002,% | 9 |
| 100003 | 100005 |     NULL |  NULL |    NULL | 0,100001,100002,100003                      |     NULL | %,100002,% | 9 |
| 100008 | 100011 |     NULL |  NULL |    NULL | 0,100001,100002,100004,100006,100007,100008 |     NULL | %,100002,% | 9 |
| 100006 | 100007 |     NULL |  NULL |    NULL | 0,100001,100002,100004,100006               |     NULL | %,100002,% | 9 |
| 100002 | 100004 |     NULL |  NULL |    NULL | 0,100001,100002                             |     NULL | %,100002,% | 9 |
| 100005 | 100010 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100005,% | 2 |
| 100005 | 100009 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100005,% | 2 |
+--------+--------+----------+-------+---------+---------------------------------------------+----------+------------+---+

并且还支持 MySQL 8.0 之前的版本等:

SELECT DP.team.parent_id AS Upline
     , DP.users.id AS UserID
     , DP.users.nickname AS Username
     , DP.users.email AS Email
     , DP.users.country AS Country
     , DP.team.gene_chain
     , DP.team.gene_num
     , p.pattern
--   , COUNT(*) OVER (PARTITION BY p.pattern) AS n   -- Not supported in 5.7 or before. We would do something else to count.
  FROM DP.team JOIN DP.users ON DP.team.user_id = DP.users.id
  JOIN (
         SELECT '%,100002,%' AS pattern UNION ALL
         SELECT '%,100005,%'
       ) AS p
    ON CONCAT('%,', DP.team.gene_chain, ',%') LIKE p.pattern
 ORDER BY p.pattern
;

结果:

+--------+--------+----------+-------+---------+---------------------------------------------+----------+------------+
| Upline | UserID | Username | Email | Country | gene_chain                                  | gene_num | pattern    |
+--------+--------+----------+-------+---------+---------------------------------------------+----------+------------+
| 100005 | 100009 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100002,% |
| 100004 | 100006 |     NULL |  NULL |    NULL | 0,100001,100002,100004                      |     NULL | %,100002,% |
| 100002 | 100003 |     NULL |  NULL |    NULL | 0,100001,100002                             |     NULL | %,100002,% |
| 100005 | 100010 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100002,% |
| 100007 | 100008 |     NULL |  NULL |    NULL | 0,100001,100002,100004,100006,100007        |     NULL | %,100002,% |
| 100003 | 100005 |     NULL |  NULL |    NULL | 0,100001,100002,100003                      |     NULL | %,100002,% |
| 100008 | 100011 |     NULL |  NULL |    NULL | 0,100001,100002,100004,100006,100007,100008 |     NULL | %,100002,% |
| 100006 | 100007 |     NULL |  NULL |    NULL | 0,100001,100002,100004,100006               |     NULL | %,100002,% |
| 100002 | 100004 |     NULL |  NULL |    NULL | 0,100001,100002                             |     NULL | %,100002,% |
| 100005 | 100009 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100005,% |
| 100005 | 100010 |     NULL |  NULL |    NULL | 0,100001,100002,100003,100005               |     NULL | %,100005,% |
+--------+--------+----------+-------+---------+---------------------------------------------+----------+------------+

测试用例的设置:

CREATE TABLE team (
    id          int  primary key auto_increment
  , user_id     int
  , parent_id   int
  , gene_chain  varchar(100)
  , gene_num    int
);

CREATE TABLE users (
    id        int  primary key
  , nickname  int
  , email     int
  , country   int
);

INSERT INTO users (id) VALUES
  ('100001')
, ('100002')
, ('100003')
, ('100004')
, ('100005')
, ('100006')
, ('100007')
, ('100008')
, ('100009')
, ('100010')
, ('100011')
, ('100012')
, ('100013')
, ('100014')
, ('100015')
;


INSERT INTO team (user_id, parent_id, gene_chain) VALUES
  (100002,   100001,   '0,100001')
, (100003,   100002,   '0,100001,100002')
, (100004,   100002,   '0,100001,100002')
, (100005,   100003,   '0,100001,100002,100003')
, (100006,   100004,   '0,100001,100002,100004')
, (100007,   100006,   '0,100001,100002,100004,100006')
, (100008,   100007,   '0,100001,100002,100004,100006,100007')
, (100009,   100005,   '0,100001,100002,100003,100005')
, (100010,   100005,   '0,100001,100002,100003,100005')
, (100011,   100008,   '0,100001,100002,100004,100006,100007,100008')
;

【讨论】:

  • 第二个查询对我有用 - 返回的行是正确的,但计数命令没有,对我来说有点太高级了
  • @ynnaij 我注意到 MySQL 5.7 或更早版本不支持 COUNT 窗口函数。这就是为什么它在该查询中被注释掉的原因。你能说一下你使用的是哪个版本吗? SELECT version(); 另外,请务必包含您需要的确切结果。如果您只需要计数,而不是所有其他详细信息,请添加该详细信息。如果需求不明确,很难提供完整的 SQL。
  • 我只需要计数,版本返回'5.7.33-2-log'
  • @ynnaij 答案已更新。第一个示例适用于 MySQL 5.7 或更高版本,仅返回找到的每个基因模式的计数。
  • 完美运行!谢谢你,希望这对将来和我一样新的人有所帮助。
【解决方案2】:
SELECT 
  DP.team.parent_id AS Upline,
  DP.users.id AS UserID, 
  DP.users.nickname AS Username, 
  DP.users.email AS Email, 
  DP.users.country AS Country, 
  DP.team.gene_chain, DP.team.gene_num
FROM (DP.team INNER JOIN DP.users ON DP.team.user_id = DP.users.id)
WHERE DP.team.gene_chain IN ('100005','100002', '100001')
ORDER BY DP.team.gene_chain;

我认为您只需要按要排序的列添加顺序。这样你将一个接一个地从给定的gene_chain获取数据。

【讨论】:

  • gene_chain 是按顺序显示的,所以用户的upline或者boss可能不是我们想要的目标ID,所以只能搜索看看gene_chain中是否存在目标ID,gene_chain的例子是' 0,100001,100002,100004,100006,100007'
  • 目标ID是什么意思?目标 ID 存在于基因链中意味着什么?
【解决方案3】:

如果我正确理解您的问题,您可以这样做:

SELECT 
  DP.team.parent_id AS Upline,
  DP.users.id AS UserID, 
  DP.users.nickname AS Username, 
  DP.users.email AS Email, 
  DP.users.country AS Country, 
  DP.team.gene_chain, DP.team.gene_num/*, (DP.team.gene_num - (SELECT DP.team.gene_num FROM DP.team WHERE DP.team.id LIKE '%100002%')) AS downline_gene*/
FROM (DP.team INNER JOIN DP.users ON DP.team.user_id = DP.users.id)
    WHERE DP.team.gene_chain IN ('100005','100002');

【讨论】:

  • 请在您的答案中添加一些解释,以便其他人可以从中学习。 OP 已经写道 OR 会混淆 ID - 你的方法如何解决这个问题?
  • 挑战是表上没有列可以帮助我们直接找到我们想要的行或者count(),我使用gene_chain来查找目标ID是否存在,如果存在那么返回的总行数就是我的答案
猜你喜欢
  • 1970-01-01
  • 2013-01-13
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多