单表上的MySQL复杂查询问题

单表上的MySQL复杂查询问题,mysql,select,nested,Mysql,Select,Nested,在尝试了几种可能性之后,我停了下来。在不让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)

在尝试了几种可能性之后,我停了下来。在不让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 ;
说明:

  • 我试图根据一棵复杂的树来调整一个人的状态。每个用户都有一个由自动增量id字段表示的id
  • 用户A已将其详细信息输入表中
  • 用户B由用户A引用,因此当输入其详细信息时,refchid1与用户A具有相同的id
  • 用户B引用用户C,其refchid1成为用户B的id,其refchid2成为用户A的id
  • 用户D被用户C引用,他的refchid1变成用户C的refchid2变成用户B的refchid3变成用户A的refchid3
  • 如果您理解上述内容的引用,您就走上了正确的道路

    上述描述的样本数据:

    (6, 'Lars', 'Luna', 'Morbi.non.sapien@enimgravida.com', 25, 0, 0, 0, 0),
    (7, 'Sonya', 'Cox', 'tellus@orci.org', 25, 6, 0, 0, 0),
    (8, 'Aiko', 'Hodge', 'vestibulum.neque.sed@vel.edu', 25, 7, 6, 0, 0),
    (9, 'Lillith', 'Bray', 'purus.Duis.elementum@necurnasuscipit.org', 25, 8, 7, 6, 0),
    (10, 'Macey', 'Hayes', 'mi.pede@aliquetodioEtiam.net', 25, 9, 8, 7, 6);
    
    我试图做到的是:

  • 默认状态为25。(25,28,30,35,40)基本上将其视为一种折扣系统,你推荐的人越多,他们推荐的人越多,你推荐的人越多,你得到的折扣就越大
  • 如果用户A至少有10个唯一用户,他引用为refchid1,则获得状态
  • 如果用户A在refchid1中至少有10个uniuque用户,而每个uniuque用户在refchid1中又有10个唯一用户,其中用户A为refchid2,则该用户将获得状态
  • 用户A在rechid1中有10个唯一用户,每个用户在refchid1中有10个唯一用户,其中用户A是rechid2,而用户A在refchid1中有10个唯一用户,其中用户A是refchid3
  • 等等
  • 如上所述,测试的结构是复杂的,我希望这样做不会使mysql服务器过载,产生数以百万计的查询。查询应该是一个更新查询,它将调整所有匹配用户的状态

    有人知道我将如何完成这项任务吗?

    你想过吗? 当您直接在表的行上更新状态,而不是通过视图(我更喜欢)动态生成状态时,我认为触发insert操作,然后创建适当的“if”语句是一个好主意

    否则,我建议不要使用status和refchid*列,而只使用一个引用“父”id的refid,然后使用视图生成状态值(关于refid的递归)。

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


    否则,我建议不要使用status和refchid*列,而只使用一个引用“父”id的refid,然后使用视图生成状态值(关于refid的递归)。

    我不知道您是如何计算点的,但此查询可能会提供足够的数据,玩它,并在公式运行时将其重写为更新查询

    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
    

    我真的不知道你是如何计算积分的,但是这个查询可能会给你足够的数据,让你在公式运行时使用它,并将它重写为一个更新查询

    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
    

    我应该创建一个用户列表和一个单独的参考表

    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
    
    然后选择链接到该用户的所有引用,并将深度添加为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
    

    我应该创建一个用户列表和一个单独的参考表

    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
    
    然后选择链接到该用户的所有引用,并将深度添加为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
    

    因此,将其视为一棵树,基本上你的意思是,在任何级别中,每引用10个用户,更高级别的所有用户都会获得1个状态点?这是一个正确的假设。说明:用户A在refchid1上有10个引用,在refchid1上的10个引用中,每个引用都有用户A在他们的refchid2上,他们在refchid1上引用了10个用户。因此,将此视为一个树,基本上你的意思是,在任何级别中,每引用10个用户,所有更高级别的用户都会获得1个状态点?这是一个正确的假设。说明:用户A在refchid1上有10个引用,在refchid1上的10个引用中,每个引用都有用户A在其refchid2上,其中每个引用都在refchid1上引用了10个用户。我以前有过类似的查询。我用40000个条目填充了数据库,仔细地设置了层次结构,这样1-116中的几个用户就可以引用其他人了。使用上面的查询,mysql服务器仍然试图在我写这篇文章时给我一个结果。运行5分钟后。返回结果花费的时间太长:)我让您建议的查询运行了45分钟,仍然没有结果:p表上有哪些键/索引?上面一个查询的描述是什么,它使用键吗?如果你看我的原始帖子,那就是我的表。ID是唯一的键/索引。从您的问题中,我推断您希望我为refchid字段设置更多的键/索引?省略索引,mysql将所有行与所有行匹配,然后对它们进行过滤,如果您为4列添加4个索引,mysql将在合并行之前进行过滤,这将大大减少时间。ALTER TABLE users添加键(refchid1)、添加键(refchid2)、添加键(refchid3)、添加键(refchid4);我以前也有过类似的疑问。我用40000个条目填充了数据库,仔细地设置了层次结构,这样1-116中的几个用户就可以引用其他人了。使用上面的查询,mysql服务器仍然试图在我写这篇文章时给我一个结果。运行5分钟后。返回结果所用的时间太长:)我让您建议的查询运行了45分钟,仍然是