mysql 存储过程 group_concat 为游标中的 select 返回 null
mysql stored procedure group_concat returning null for select in cursor
我有一个存储过程,我在其中循环访问游标中的结果。我遇到的问题是 license_attributes 值在不应该的情况下始终为 null。如果我在存储过程外部执行 select 语句,或者作为调试在存储过程中的游标外部执行 select 语句,我会得到我期望的结果(不为空)
这是 select 中始终在游标中返回 null 的部分:
(SELECT
CONCAT('{""',sf.Asset_Attribute__c.Type__c,'"": {',GROUP_CONCAT(
'""',sf.Asset_Attribute__c.Key__c,'"":""',LOWER(sf.Asset_Attribute__c.Value__c),'""'
),'}}')
FROM
sf.Asset_Attribute__c
WHERE
sf.Asset_Attribute__c.Asset__c = license_id
GROUP BY sf.Asset_Attribute__c.Asset__c) AS `license_attributes`
这是存储过程的部分:
GETCLOUDACCOUNTS:BEGIN
DECLARE no_more_cloud_accounts_records boolean DEFAULT FALSE;
DECLARE company VARCHAR(255) DEFAULT null;
DECLARE license_status VARCHAR(50) DEFAULT null;
DECLARE license_id VARCHAR(18) DEFAULT null;
DECLARE cloud_owner_email VARCHAR(255) DEFAULT null;
DECLARE entitlement_plan VARCHAR(255) DEFAULT null;
DECLARE role VARCHAR(500) DEFAULT null;
DECLARE is_trial BOOLEAN DEFAULT false;
DECLARE license_attributes VARCHAR(2000) DEFAULT null;
DECLARE zuora_account_id VARCHAR(100) DEFAULT '';
DECLARE zuora_account_number VARCHAR(50) DEFAULT null;
DECLARE zuora_account_status VARCHAR(50) DEFAULT null;
DECLARE zuora_account_last_invoice_date DATETIME DEFAULT null;
DECLARE has_active_subscriptions BOOLEAN DEFAULT false;
DECLARE cloud_accounts_cursor CURSOR FOR
SELECT
(SELECT `sf`.`Contact`.`CompanyName__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `company`,
`sf`.`License_Key_Association__c`.`License_Key_Status__c` AS `license_status`,
`sf`.`License_Key_Association__c`.`License_Key__c` AS `license_id`,
`sf`.`Asset`.`ContactEmail__c` AS `cloud_owner_email`,
(SELECT `sf`.`Contact`.`CloudEntitlementPlan__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `entitlement_plan`,
`sf`.`License_Key_Association__c`.`Role__c` AS `role`,
IF( (SELECT `sf`.`Product2`.`IsCommercial__c` FROM `sf`.`Product2` WHERE `sf`.`Product2`.`Id`=`sf`.`Asset`.`Product2Id`) = 0,true,false ) AS `is_trial`,
(SELECT
CONCAT('{""',sf.Asset_Attribute__c.Type__c,'"": {',GROUP_CONCAT(
'""',sf.Asset_Attribute__c.Key__c,'"":""',LOWER(sf.Asset_Attribute__c.Value__c),'""'
),'}}')
FROM
sf.Asset_Attribute__c
WHERE
sf.Asset_Attribute__c.Asset__c = license_id
GROUP BY sf.Asset_Attribute__c.Asset__c) AS `license_attributes`
FROM
`sf`.`License_Key_Association__c`
LEFT JOIN `sf`.`Asset`
ON `sf`.`License_Key_Association__c`.`License_Key__c` = `sf`.`Asset`.`Id`
JOIN `sf`.`Contact`
ON `sf`.`Contact`.`Id` = `sf`.`License_Key_Association__c`.`Contact__c`
WHERE
`sf`.`Contact`.`ExternalID__c`='someexternalidhere';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_cloud_accounts_records = true;
SELECT
(SELECT `sf`.`Contact`.`CompanyName__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `company`,
`sf`.`License_Key_Association__c`.`License_Key_Status__c` AS `license_status`,
`sf`.`License_Key_Association__c`.`License_Key__c` AS `license_id`,
`sf`.`Asset`.`ContactEmail__c` AS `cloud_owner_email`,
(SELECT `sf`.`Contact`.`CloudEntitlementPlan__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `entitlement_plan`,
`sf`.`License_Key_Association__c`.`Role__c` AS `role`,
IF( (SELECT `sf`.`Product2`.`IsCommercial__c` FROM `sf`.`Product2` WHERE `sf`.`Product2`.`Id`=`sf`.`Asset`.`Product2Id`) = 0,true,false ) AS `is_trial`,
(SELECT
CONCAT('{""',sf.Asset_Attribute__c.Type__c,'"": {',GROUP_CONCAT(
'""',sf.Asset_Attribute__c.Key__c,'"":""',LOWER(sf.Asset_Attribute__c.Value__c),'""'
),'}}')
FROM
sf.Asset_Attribute__c
WHERE
sf.Asset_Attribute__c.Asset__c = license_id
GROUP BY sf.Asset_Attribute__c.Asset__c) AS `license_attributes`
FROM
`sf`.`License_Key_Association__c`
LEFT JOIN `sf`.`Asset`
ON `sf`.`License_Key_Association__c`.`License_Key__c` = `sf`.`Asset`.`Id`
JOIN `sf`.`Contact`
ON `sf`.`Contact`.`Id` = `sf`.`License_Key_Association__c`.`Contact__c`
WHERE
`sf`.`Contact`.`ExternalID__c`=@p_externalId;
OPEN cloud_accounts_cursor;
CLOUDACCOUNTSLOOP: loop
fetch cloud_accounts_cursor into company, license_status, license_id, cloud_owner_email, entitlement_plan, role, is_trial, license_attributes;
IF is_trial = true THEN
SET has_active_subscriptions = true;
END IF;
SET zuora_account_id = `z`.`getZAccountId`(cloud_owner_email);
IF zuora_account_id IS NOT NULL THEN
SELECT `accountNumber`,`status`,`lastInvoiceDate` INTO zuora_account_number,zuora_account_status,zuora_account_last_invoice_date FROM zuora.Account WHERE id=zuora_account_id;
IF has_active_subscriptions = false THEN
SET has_active_subscriptions = (SELECT IF((SELECT COUNT(*) FROM `z`.`RatePlan`
RIGHT JOIN `z`.`ProductRatePlan` ON `z`.`RatePlan`.`productRatePlanId` = `z`.`ProductRatePlan`.`id`
LEFT JOIN `z`.`Subscription` ON `z`.`RatePlan`.`subscriptionId` = `z`.`Subscription`.`id`
WHERE
`z`.`ProductRatePlan`.`wowzaRatePlanCode__c` IN ( (SELECT `code` FROM `z`.`zCloudRatePlanCodes`) )
AND `z`.`Subscription`.`status` = 'Active'
AND `z`.`Subscription`.`accountId` = zuora_account_id ) > 0, true, false));
END IF;
END IF;
REPLACE INTO `sf`.`zCloudAccounts` (`user_email`,`company`,`license_status`,`license_id`,`cloud_owner_email`,`entitlement_plan`,`role`,`is_trial`,`attributes`,`zuora_account_id`,`zuora_account_number`,`zuora_account_status`,`zuora_account_last_invoice_date`,`has_active_subscriptions`) VALUES(@p_userEmail,company,license_status,license_id,cloud_owner_email,entitlement_plan,role,is_trial,license_attributes,zuora_account_id,zuora_account_number,zuora_account_status,zuora_account_last_invoice_date,has_active_subscriptions);
IF no_more_cloud_accounts_records THEN
CLOSE cloud_accounts_cursor;
LEAVE CLOUDACCOUNTSLOOP;
end if;
END LOOP CLOUDACCOUNTSLOOP;
END GETCLOUDACCOUNTS;
如果我在 GETCLOUDACCOUNTS 块之外执行完整的 select stateout,我会得到预期的结果:
company, license_status, license_id, cloud_owner_email, entitlement_plan, role, is_trial, license_attributes
Test Company, Active, 02iq0000000jKgMAAU, myemail@email.com, Standard, Owner, 0, {""cloud"": {""cloud_num_247_t_streams"":""0"",""cloud_num_247_p_streams"":""0""}}
Test Company, Active, 02iq0000000xlBBAAY, otheremail@email.com, Standard, Admin;wcl_admin;wcl_support, 0, {""cloud"": {""cloud_num_247_t_streams"":""1"",""cloud_num_247_p_streams"":""1"",""test_attribute"":""true"",""api_access"":""true""}}
但是块内的结果显示 license_attributes 为空:
company, license_status, license_id, cloud_owner_email, entitlement_plan, role, is_trial, license_attributes
Test Company, Active, 02iq0000000jKgMAAU, myemail@email.com, Standard, Owner, 0, null
Test Company, Active, 02iq0000000xlBBAAY, otheremail@email.com, Standard, Admin;wcl_admin;wcl_support, 0, null
非常感谢任何帮助!
您可以 COALESCE
处理 GROUP_CONCAT
中的 NULL 值
COALESCE(`YourColumnName`,'')
您还可以使用明显不同的字符串来显示 NULL 值的来源,以便您可以修复查询。
COALESCE(`YourColumnName`,'**UNEXPECTED NULL**')
我怀疑问题与过程变量有关 license_id
。
SELECT 列表中的相关子选择包括
WHERE sf.Asset_Attribute__c.Asset__c = license_id
^^^^^^^^^^
局部变量优先于列引用。由于 license_id
在代码块中声明为变量,
DECLARE license_id VARCHAR(18) DEFAULT null;
SELECT 语句中对 license_id
的引用是对该过程变量的引用。
在代码块之外,可能没有名为 license_id
的局部变量。所以同一个 SQL SELECT 语句,对 license_id
的引用不是对变量的引用,而是对列的引用。
我还没有跟踪所有的逻辑,或者 license_id
变量的内容。但我怀疑这解释了在代码块内与块外执行的语句观察到的行为差异。
我有一个存储过程,我在其中循环访问游标中的结果。我遇到的问题是 license_attributes 值在不应该的情况下始终为 null。如果我在存储过程外部执行 select 语句,或者作为调试在存储过程中的游标外部执行 select 语句,我会得到我期望的结果(不为空)
这是 select 中始终在游标中返回 null 的部分:
(SELECT
CONCAT('{""',sf.Asset_Attribute__c.Type__c,'"": {',GROUP_CONCAT(
'""',sf.Asset_Attribute__c.Key__c,'"":""',LOWER(sf.Asset_Attribute__c.Value__c),'""'
),'}}')
FROM
sf.Asset_Attribute__c
WHERE
sf.Asset_Attribute__c.Asset__c = license_id
GROUP BY sf.Asset_Attribute__c.Asset__c) AS `license_attributes`
这是存储过程的部分:
GETCLOUDACCOUNTS:BEGIN
DECLARE no_more_cloud_accounts_records boolean DEFAULT FALSE;
DECLARE company VARCHAR(255) DEFAULT null;
DECLARE license_status VARCHAR(50) DEFAULT null;
DECLARE license_id VARCHAR(18) DEFAULT null;
DECLARE cloud_owner_email VARCHAR(255) DEFAULT null;
DECLARE entitlement_plan VARCHAR(255) DEFAULT null;
DECLARE role VARCHAR(500) DEFAULT null;
DECLARE is_trial BOOLEAN DEFAULT false;
DECLARE license_attributes VARCHAR(2000) DEFAULT null;
DECLARE zuora_account_id VARCHAR(100) DEFAULT '';
DECLARE zuora_account_number VARCHAR(50) DEFAULT null;
DECLARE zuora_account_status VARCHAR(50) DEFAULT null;
DECLARE zuora_account_last_invoice_date DATETIME DEFAULT null;
DECLARE has_active_subscriptions BOOLEAN DEFAULT false;
DECLARE cloud_accounts_cursor CURSOR FOR
SELECT
(SELECT `sf`.`Contact`.`CompanyName__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `company`,
`sf`.`License_Key_Association__c`.`License_Key_Status__c` AS `license_status`,
`sf`.`License_Key_Association__c`.`License_Key__c` AS `license_id`,
`sf`.`Asset`.`ContactEmail__c` AS `cloud_owner_email`,
(SELECT `sf`.`Contact`.`CloudEntitlementPlan__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `entitlement_plan`,
`sf`.`License_Key_Association__c`.`Role__c` AS `role`,
IF( (SELECT `sf`.`Product2`.`IsCommercial__c` FROM `sf`.`Product2` WHERE `sf`.`Product2`.`Id`=`sf`.`Asset`.`Product2Id`) = 0,true,false ) AS `is_trial`,
(SELECT
CONCAT('{""',sf.Asset_Attribute__c.Type__c,'"": {',GROUP_CONCAT(
'""',sf.Asset_Attribute__c.Key__c,'"":""',LOWER(sf.Asset_Attribute__c.Value__c),'""'
),'}}')
FROM
sf.Asset_Attribute__c
WHERE
sf.Asset_Attribute__c.Asset__c = license_id
GROUP BY sf.Asset_Attribute__c.Asset__c) AS `license_attributes`
FROM
`sf`.`License_Key_Association__c`
LEFT JOIN `sf`.`Asset`
ON `sf`.`License_Key_Association__c`.`License_Key__c` = `sf`.`Asset`.`Id`
JOIN `sf`.`Contact`
ON `sf`.`Contact`.`Id` = `sf`.`License_Key_Association__c`.`Contact__c`
WHERE
`sf`.`Contact`.`ExternalID__c`='someexternalidhere';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_cloud_accounts_records = true;
SELECT
(SELECT `sf`.`Contact`.`CompanyName__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `company`,
`sf`.`License_Key_Association__c`.`License_Key_Status__c` AS `license_status`,
`sf`.`License_Key_Association__c`.`License_Key__c` AS `license_id`,
`sf`.`Asset`.`ContactEmail__c` AS `cloud_owner_email`,
(SELECT `sf`.`Contact`.`CloudEntitlementPlan__c` FROM `sf`.`Contact` WHERE `sf`.`Asset`.`ContactId`=`sf`.`Contact`.`Id`) AS `entitlement_plan`,
`sf`.`License_Key_Association__c`.`Role__c` AS `role`,
IF( (SELECT `sf`.`Product2`.`IsCommercial__c` FROM `sf`.`Product2` WHERE `sf`.`Product2`.`Id`=`sf`.`Asset`.`Product2Id`) = 0,true,false ) AS `is_trial`,
(SELECT
CONCAT('{""',sf.Asset_Attribute__c.Type__c,'"": {',GROUP_CONCAT(
'""',sf.Asset_Attribute__c.Key__c,'"":""',LOWER(sf.Asset_Attribute__c.Value__c),'""'
),'}}')
FROM
sf.Asset_Attribute__c
WHERE
sf.Asset_Attribute__c.Asset__c = license_id
GROUP BY sf.Asset_Attribute__c.Asset__c) AS `license_attributes`
FROM
`sf`.`License_Key_Association__c`
LEFT JOIN `sf`.`Asset`
ON `sf`.`License_Key_Association__c`.`License_Key__c` = `sf`.`Asset`.`Id`
JOIN `sf`.`Contact`
ON `sf`.`Contact`.`Id` = `sf`.`License_Key_Association__c`.`Contact__c`
WHERE
`sf`.`Contact`.`ExternalID__c`=@p_externalId;
OPEN cloud_accounts_cursor;
CLOUDACCOUNTSLOOP: loop
fetch cloud_accounts_cursor into company, license_status, license_id, cloud_owner_email, entitlement_plan, role, is_trial, license_attributes;
IF is_trial = true THEN
SET has_active_subscriptions = true;
END IF;
SET zuora_account_id = `z`.`getZAccountId`(cloud_owner_email);
IF zuora_account_id IS NOT NULL THEN
SELECT `accountNumber`,`status`,`lastInvoiceDate` INTO zuora_account_number,zuora_account_status,zuora_account_last_invoice_date FROM zuora.Account WHERE id=zuora_account_id;
IF has_active_subscriptions = false THEN
SET has_active_subscriptions = (SELECT IF((SELECT COUNT(*) FROM `z`.`RatePlan`
RIGHT JOIN `z`.`ProductRatePlan` ON `z`.`RatePlan`.`productRatePlanId` = `z`.`ProductRatePlan`.`id`
LEFT JOIN `z`.`Subscription` ON `z`.`RatePlan`.`subscriptionId` = `z`.`Subscription`.`id`
WHERE
`z`.`ProductRatePlan`.`wowzaRatePlanCode__c` IN ( (SELECT `code` FROM `z`.`zCloudRatePlanCodes`) )
AND `z`.`Subscription`.`status` = 'Active'
AND `z`.`Subscription`.`accountId` = zuora_account_id ) > 0, true, false));
END IF;
END IF;
REPLACE INTO `sf`.`zCloudAccounts` (`user_email`,`company`,`license_status`,`license_id`,`cloud_owner_email`,`entitlement_plan`,`role`,`is_trial`,`attributes`,`zuora_account_id`,`zuora_account_number`,`zuora_account_status`,`zuora_account_last_invoice_date`,`has_active_subscriptions`) VALUES(@p_userEmail,company,license_status,license_id,cloud_owner_email,entitlement_plan,role,is_trial,license_attributes,zuora_account_id,zuora_account_number,zuora_account_status,zuora_account_last_invoice_date,has_active_subscriptions);
IF no_more_cloud_accounts_records THEN
CLOSE cloud_accounts_cursor;
LEAVE CLOUDACCOUNTSLOOP;
end if;
END LOOP CLOUDACCOUNTSLOOP;
END GETCLOUDACCOUNTS;
如果我在 GETCLOUDACCOUNTS 块之外执行完整的 select stateout,我会得到预期的结果:
company, license_status, license_id, cloud_owner_email, entitlement_plan, role, is_trial, license_attributes
Test Company, Active, 02iq0000000jKgMAAU, myemail@email.com, Standard, Owner, 0, {""cloud"": {""cloud_num_247_t_streams"":""0"",""cloud_num_247_p_streams"":""0""}}
Test Company, Active, 02iq0000000xlBBAAY, otheremail@email.com, Standard, Admin;wcl_admin;wcl_support, 0, {""cloud"": {""cloud_num_247_t_streams"":""1"",""cloud_num_247_p_streams"":""1"",""test_attribute"":""true"",""api_access"":""true""}}
但是块内的结果显示 license_attributes 为空:
company, license_status, license_id, cloud_owner_email, entitlement_plan, role, is_trial, license_attributes
Test Company, Active, 02iq0000000jKgMAAU, myemail@email.com, Standard, Owner, 0, null
Test Company, Active, 02iq0000000xlBBAAY, otheremail@email.com, Standard, Admin;wcl_admin;wcl_support, 0, null
非常感谢任何帮助!
您可以 COALESCE
处理 GROUP_CONCAT
COALESCE(`YourColumnName`,'')
您还可以使用明显不同的字符串来显示 NULL 值的来源,以便您可以修复查询。
COALESCE(`YourColumnName`,'**UNEXPECTED NULL**')
我怀疑问题与过程变量有关 license_id
。
SELECT 列表中的相关子选择包括
WHERE sf.Asset_Attribute__c.Asset__c = license_id
^^^^^^^^^^
局部变量优先于列引用。由于 license_id
在代码块中声明为变量,
DECLARE license_id VARCHAR(18) DEFAULT null;
SELECT 语句中对 license_id
的引用是对该过程变量的引用。
在代码块之外,可能没有名为 license_id
的局部变量。所以同一个 SQL SELECT 语句,对 license_id
的引用不是对变量的引用,而是对列的引用。
我还没有跟踪所有的逻辑,或者 license_id
变量的内容。但我怀疑这解释了在代码块内与块外执行的语句观察到的行为差异。