Home > Software engineering >  Nested MySQL selects issue within WordPress usermeta table
Nested MySQL selects issue within WordPress usermeta table

Time:10-29

Having an issue with a complex MySql select statement and hoping for some pointers!

So I am using a number of plugins on top of WordPress with some interesting ways of storing data. The bits I'm concerned with are as following: There are some 'parent' accounts which have a number of child accounts. The parent to child relationship is stored in the usermeta table (user_id=user_id of child account, meta_value = parent_id, meta_key='parent'). Each of these child accounts can also complete a number of tasks. This is also stored in the usermeta table (user_id=user_id of child account, meta_value = complete_status, meta_key='task_id_'.task_id).

I'm trying to create a view where I get a list of each of these parent accounts, along with a few bits of information, then a few derived values from their children, including the average number of completed tasks by the children of each parent.

This is my MySQL statement, the part that is having the issue is the nested select:

SELECT 
wp_parent_account_info_table.obj_id, 
wp_parent_account_info_table.obj_type, 
wp_parent_account_info_table.id, 
wp_other_custom_table_info.created_at, 
wp_other_custom_table_info.product_id, 
(SELECT AVG(cc.rcount) 
    FROM (SELECT DISTINCT COUNT(*) as rcount 
        FROM wp_usermeta 
        WHERE meta_key LIKE 'task_id_%' 
        AND meta_value = 'complete' 
        AND wp_usermeta.user_id IN (SELECT DISTINCT user_id 
            FROM wp_usermeta 
            WHERE meta_key = 'parent' 
            AND meta_value = wp_parent_account_info_table.id
            ) AS sc
        ) AS cc
    ) AS a 
FROM wp_parent_account_info_table 
JOIN wp_other_custom_table_info 
ON `wp_parent_account_info_table`.`obj_id`=`wp_other_custom_table_info`.`id` 
INNER JOIN wp_another_custom_table_info 
ON `wp_another_custom_table_info`.`subscription_id`=`wp_parent_account_info_table`.`obj_id` WHERE `wp_parent_account_info_table`.`status` = 'enabled' 
AND `wp_parent_account_info_table`.`sub_accounts_available` <> '0' 
AND `wp_other_custom_table_info`.`status` = 'active' 
AND (`wp_another_custom_table_info`.`expires_at` > CONCAT(CURDATE(), ' 23:59:59') 
OR `wp_another_custom_table_info`.`expires_at` = '0000-00-00 00:00:00') 
LIMIT 0,30;

I've tried to make this readable, apologies for complexity. I didn't want to remove any parts incase they were relevant.

The statement works fine without the nested select. It also works (has no error) if I replace the most nested select with an array of IDs (so just putting: IN (1,2,3)). Is this something about me trying to get the parent ID from too far down?

This is the error: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS sc) AS cc) AS a FROM wp_parent_account_info_table JOIN wp_other_custom_table_info ON'

Any pointers would be much appreciated.

Edit:

Along with the answer below which resolved this error, I also didn't have access to the id variable in the furthest nest (a new error!), so I split them into an extra column. Here is my final code:

 SELECT 
    wp_parent_account_info_table.obj_id, 
    wp_parent_account_info_table.obj_type, 
    wp_parent_account_info_table.id, 
    wp_other_custom_table_info.created_at, 
    wp_other_custom_table_info.product_id, 
    (SELECT DISTINCT COUNT(*) 
    FROM wp_usermeta
    WHERE meta_key = 'parent' 
    AND meta_value = wp_parent_account_info_table.id) as c,
    (SELECT DISTINCT COUNT(*) as rcount 
    FROM wp_usermeta 
    WHERE meta_key LIKE 'task_id_%' 
    AND meta_value = 'complete' 
    AND wp_usermeta.user_id IN (SELECT DISTINCT user_id 
        FROM wp_usermeta 
        WHERE meta_key = 'parent' 
        AND meta_value = wp_parent_account_info_table.id
        ) 
    ) AS a,
    (SELECT a / c)
    FROM wp_parent_account_info_table 
    JOIN wp_other_custom_table_info 
    ON `wp_parent_account_info_table`.`obj_id`=`wp_other_custom_table_info`.`id` 
    INNER JOIN wp_another_custom_table_info 
    ON `wp_another_custom_table_info`.`subscription_id`=`wp_parent_account_info_table`.`obj_id` WHERE `wp_parent_account_info_table`.`status` = 'enabled' 
    AND `wp_parent_account_info_table`.`sub_accounts_available` <> '0' 
    AND `wp_other_custom_table_info`.`status` = 'active' 
    AND (`wp_another_custom_table_info`.`expires_at` > CONCAT(CURDATE(), ' 23:59:59') 
    OR `wp_another_custom_table_info`.`expires_at` = '0000-00-00 00:00:00') 
    LIMIT 0,30;

CodePudding user response:

The syntax error is related to your IN cluse ... the IN clause base on a subselect don't require a tablename alias then avoid the sc after the )

    SELECT 
    wp_parent_account_info_table.obj_id, 
    wp_parent_account_info_table.obj_type, 
    wp_parent_account_info_table.id, 
    wp_other_custom_table_info.created_at, 
    wp_other_custom_table_info.product_id, 
    (SELECT AVG(cc.rcount) 
        FROM (SELECT DISTINCT COUNT(*) as rcount 
            FROM wp_usermeta 
            WHERE meta_key LIKE 'task_id_%' 
            AND meta_value = 'complete' 
            AND wp_usermeta.user_id IN (SELECT DISTINCT user_id 
                FROM wp_usermeta 
                WHERE meta_key = 'parent' 
                AND meta_value = wp_parent_account_info_table.id
                ) 
            ) AS cc
        ) AS a 
    FROM wp_parent_account_info_table 
    JOIN wp_other_custom_table_info 
    ON `wp_parent_account_info_table`.`obj_id`=`wp_other_custom_table_info`.`id` 
    INNER JOIN wp_another_custom_table_info 
    ON `wp_another_custom_table_info`.`subscription_id`=`wp_parent_account_info_table`.`obj_id` WHERE `wp_parent_account_info_table`.`status` = 'enabled' 
    AND `wp_parent_account_info_table`.`sub_accounts_available` <> '0' 
    AND `wp_other_custom_table_info`.`status` = 'active' 
    AND (`wp_another_custom_table_info`.`expires_at` > CONCAT(CURDATE(), ' 23:59:59') 
    OR `wp_another_custom_table_info`.`expires_at` = '0000-00-00 00:00:00') 
    LIMIT 0,30;
  • Related