MySQL单表复杂查询问题

发布于 2024-11-28 16:52:50 字数 2436 浏览 0 评论 0原文

在尝试了几种可能性之后,我停了下来。在不使 mysql 服务器因数百个查询而超载的情况下,这就是我想要实现的目标:

这是表格

    CREATE TABLE `users` (
  `id` int(11) NOT NULL auto_increment,
  `firstname` varchar(64) NOT NULL,
  `lastname` varchar(64) NOT NULL,
  `email` varchar(64) NOT NULL,
  `status` smallint(5) NOT NULL,
  `refchid1` int(11) NOT NULL,
  `refchid2` int(11) NOT NULL,
  `refchid3` int(11) NOT NULL,
  `refchid4` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

说明:

  1. 我试图根据复杂的树调整一个人的状态。每个用户都有一个由 auto_increment id 字段表示的 id。
  2. 用户 A 将其详细信息输入到表中。
  3. 用户 B 被用户 A 引用,因此当输入他的详细信息时,refchid1 与用户 A 具有相同的 id。
  4. 用户 C 被用户 B 引用,他的 refchid1 成为用户 B 的 id,他的 refchid2 成为用户 A 的 id
  5. 。 D 被用户 C 引用,他的 refchid1 变为用户 C 的引用,refchid2 变为用户 B 的引用,refchid3 变为用户 A 的引用

。如上所述,您走在正确的道路上。

上述描述的示例数据:

(6, 'Lars', 'Luna', '[email protected]', 25, 0, 0, 0, 0),
(7, 'Sonya', 'Cox', '[email protected]', 25, 6, 0, 0, 0),
(8, 'Aiko', 'Hodge', '[email protected]', 25, 7, 6, 0, 0),
(9, 'Lillith', 'Bray', '[email protected]', 25, 8, 7, 6, 0),
(10, 'Macey', 'Hayes', '[email protected]', 25, 9, 8, 7, 6);

我想要完成的是:

  1. 默认状态是 25。(25,28,30,35,40)基本上将其视为折扣系统,您推荐的人越多,人就越多他们将您推荐到原始推荐人所在的位置,您将获得更大的折扣。
  2. 如果用户 A 拥有至少 10 个被引用为 refchid1 的唯一用户,他将获得状态。
  3. 如果用户 A 在 refchid1 中至少有 10 个唯一用户,而每个用户又在 refchid1 中拥有 10 个唯一用户,其中用户 A 是 refchid2,则他将获得状态。
  4. 用户 A 在 rechid1 中拥有 10 个唯一用户,每个用户在 refchid1 中拥有 10 个唯一用户,其中用户 A 是 rechid2,而 rechid2 又在 refchid1 中拥有 10 个唯一用户,其中用户 A 是 refchid3。
  5. 如上所述

,测试的结构很复杂,我希望在不使 mysql 服务器因数百万个查询而超载的情况下进行测试。该查询应该是更新查询,它将调整所有匹配用户的状态。

有谁知道我将如何实现这一目标的解决方案?

Having tried several possibilities I have come to a stop. Without overloading the mysql server with hundreds of queries, this is what I am trying to achieve:

Here is the table

    CREATE TABLE `users` (
  `id` int(11) NOT NULL auto_increment,
  `firstname` varchar(64) NOT NULL,
  `lastname` varchar(64) NOT NULL,
  `email` varchar(64) NOT NULL,
  `status` smallint(5) NOT NULL,
  `refchid1` int(11) NOT NULL,
  `refchid2` int(11) NOT NULL,
  `refchid3` int(11) NOT NULL,
  `refchid4` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

Explanation:

  1. I am trying to adjust a person's status based on a complex tree. Each user has an id as denoted by the auto_increment id field.
  2. User A has his details entered into the table.
  3. User B is refered by User A, so when his details are entered refchid1 has the same id as User A.
  4. User C is refered by User B, his refchid1 becomes the id of User B and his refchid2 becomes the id of User A.
  5. User D is refered by User C, his refchid1 becomes that of User C, refchid2 that of UserB and refchid3 that of User A.

If you understand the referencing of the above, you are on the right track.

Sample Data of above description:

(6, 'Lars', 'Luna', '[email protected]', 25, 0, 0, 0, 0),
(7, 'Sonya', 'Cox', '[email protected]', 25, 6, 0, 0, 0),
(8, 'Aiko', 'Hodge', '[email protected]', 25, 7, 6, 0, 0),
(9, 'Lillith', 'Bray', '[email protected]', 25, 8, 7, 6, 0),
(10, 'Macey', 'Hayes', '[email protected]', 25, 9, 8, 7, 6);

What I am trying to accomplish is this:

  1. The default status is 25. (25,28,30,35,40) See this basically as a discount system, where the more people you refer and the more people they refer where you where the originating referer, you receive larger discounts.
  2. If User A has at least 10 unique users he has referenced as refchid1 he gains status.
  3. If User A has at least 10 uniuque users in refchid1 that each in turn has 10 unique users in refchid1 where User A is refchid2, he gains status.
  4. User A has 10 unique users in rechid1 that each have 10 unique users in refchid1 where user A is rechid2 that in turn have 10 unique users in refchid1 where user A is refchid3.
  5. etc.

As stated, the structure of testing is complex and I wish to do this without overloading the mysql server with millions of queries. The query should be an UPDATE query that will adjust the status of all matching users.

Does anyone have a solution of how I am going to accomplish this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

°如果伤别离去 2024-12-05 16:52:50

我真的不知道你是如何计算这些点的,但是这个查询可能会为你提供足够的数据来处理、使用它,并在你让公式工作时将其重写为更新查询。

SELECT
 parent.*,
 SUM(IF(parent.id = child.refchid1, 1, 0)) AS count_ref1,
 SUM(IF(parent.id = child.refchid2, 1, 0)) AS count_ref2,
 SUM(IF(parent.id = child.refchid3, 1, 0)) AS count_ref3,
 SUM(IF(parent.id = child.refchid4, 1, 0)) AS count_ref4,
 COUNT(child.id) as count_ref
FROM users AS parent 
LEFT JOIN users AS child 
    ON (  parent.id = child.refchid1 
       OR parent.id = child.refchid2 
       OR parent.id = child.refchid3 
       OR parent.id = child.refchid4)
GROUP BY parent.id

I don't really got how you calculated the points, but this query probably give you enough data to work with, play with it and rewrite it to an update query when you got the formula working.

SELECT
 parent.*,
 SUM(IF(parent.id = child.refchid1, 1, 0)) AS count_ref1,
 SUM(IF(parent.id = child.refchid2, 1, 0)) AS count_ref2,
 SUM(IF(parent.id = child.refchid3, 1, 0)) AS count_ref3,
 SUM(IF(parent.id = child.refchid4, 1, 0)) AS count_ref4,
 COUNT(child.id) as count_ref
FROM users AS parent 
LEFT JOIN users AS child 
    ON (  parent.id = child.refchid1 
       OR parent.id = child.refchid2 
       OR parent.id = child.refchid3 
       OR parent.id = child.refchid4)
GROUP BY parent.id
江湖彼岸 2024-12-05 16:52:50

我应该创建一个用户列表和一个单独的引用表,

CREATE TABLE reference
(
    reference_id SERIAL,
    new_user_id BIGINT UNSIGNED NOT NULL,
    refered_user_id BIGINT UNSIGNED NOT NULL,
    reference_depth INT UNSIGNED NOT NULL
);

当您添加新用户时,如果该用户被另一个用户引用,请添加一行深度为 1 的行,

INSERT INTO reference SET
    new_user_id = $new_user_id, 
    refered_user_id =  $refered_user_id, 
    reference_depth = 1

然后选择链接到该用户的所有引用并添加深度whit 1:

INSERT INTO reference (new_user_id, refered_user_id, reference_depth)
SELECT $new_user_id, refered_user_id, reference_depth +1
FROM reference WHERE new_user_id = $refered_user_id;

然后计算点

SELECT
  SUM(
    IF(reference_depth = 1, 10, 0) 
    + IF(reference_depth = 2, 3, 0) 
    + IF(reference_depth = 3, 2, 0)
    + IF(reference_depth > 3, 1, 0)
  )
FROM reference
WHERE new_user_id = $user_id

i should have created a list of user, and a seperate table for references,

CREATE TABLE reference
(
    reference_id SERIAL,
    new_user_id BIGINT UNSIGNED NOT NULL,
    refered_user_id BIGINT UNSIGNED NOT NULL,
    reference_depth INT UNSIGNED NOT NULL
);

and when you add a new user, if that user was refered by another user, add one row whit depth 1,

INSERT INTO reference SET
    new_user_id = $new_user_id, 
    refered_user_id =  $refered_user_id, 
    reference_depth = 1

then select all references linked to that user and add depth whit 1:

INSERT INTO reference (new_user_id, refered_user_id, reference_depth)
SELECT $new_user_id, refered_user_id, reference_depth +1
FROM reference WHERE new_user_id = $refered_user_id;

and then to calculate points

SELECT
  SUM(
    IF(reference_depth = 1, 10, 0) 
    + IF(reference_depth = 2, 3, 0) 
    + IF(reference_depth = 3, 2, 0)
    + IF(reference_depth > 3, 1, 0)
  )
FROM reference
WHERE new_user_id = $user_id
难忘№最初的完美 2024-12-05 16:52:50

您是否考虑过 触发器
当您直接在表的行上更新状态而不是通过视图动态生成状态(我更喜欢)时,我认为触发插入操作然后创建正确的“if”语句可能是一个好主意。

否则,我建议不要使用 statusrefchid* 列,而只使用一个 refid ,它引用“父”id,然后使用视图来生成状态值(递归地考虑refid)。

Did you think about triggers ?
As you are updating the status directly on the table's rows and not generating it dynamically through a view (which I prefer) I think that triggering an insert action and then creating the proper "if" statements can be a good idea.

Otherwise I would recommend not using status and refchid* columns but only one refid which refers to the "parent" id and then using a view to generate the status value (regarding recursivelly the refid).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文