In some cases there is a need to change the backend type of a catalog product attribute from varchar to text. The purpose of this change is to get more than 255 characters space for a string value.
In this article I will cover the situation when problems occur after changing the backend type of an attribute.
The Problem
If the backend type of an attribute is changed, e.g. via install/upgrade script, Magento does not automatically copy and clean up old values. The consequence of that is that there are rudiments in the EAV value tables which cause some side effects. One of the side effects I was facing is editing a product which had a value for the affected attribute before the backend type change (in admin area). No values are displayed and there is no possibility to set a new value.
So what to do if the change already happened and there is a mix between old value table rudiments and new value table entries?
The Solution
One possible solution to solve the issue are the following SQL Statements, here is an example for changing from varchar to text (you need to find out the id of the attribute from the eav_attribute table – here {attribute_id}):
1. Copy the “value” from varchar table to text table for the case an entry for a product entity exists in both tables, but only if the “value” in the text table is null:
UPDATE catalog_product_entity_varchar, catalog_product_entity_text SET catalog_product_entity_text.value = catalog_product_entity_varchar.value WHERE catalog_product_entity_varchar.attribute_id = catalog_product_entity_text.attribute_id AND catalog_product_entity_varchar.entity_id = catalog_product_entity_text.entity_id AND catalog_product_entity_text.store_id = catalog_product_entity_varchar.store_id AND catalog_product_entity_text.entity_type_id = catalog_product_entity_varchar.entity_type_id AND catalog_product_entity_text.value is null AND catalog_product_entity_varchar.attribute_id = {attribute_id};
2. Copy entries which do not exist in text value table, but exist in the varchar table
INSERT IGNORE INTO catalog_product_entity_text (entity_type_id, store_id, attribute_id, entity_id, value) select entity_type_id, store_id, attribute_id, entity_id, value from catalog_product_entity_varchar where catalog_product_entity_varchar.attribute_id = {attribute_id} and catalog_product_entity_varchar.value is not null;
3. Delete entries from the varchar table
DELETE FROM catalog_product_entity_varchar where attribute_id = {attribute_id};
Important note
Please verify the SQL, whether it is suitable for your purpose. Best practice is also to test it in a local / staging system and to back up the live database before applying the SQL on production. The solution is not perfect: I myself faced the issue, that the enterprise indexer cronjob took about 4h after applying the SQL, which blocked other cronjobs to be executed (about 50K products in DB). Possible way to avoid this is to separate “malways” (enterprise indexer) and “mdefault” cronjobs.
I hope this can be helpful. Feel free to comment if you faced this issue too or if you have any additions or a better solution.
Magento Certified Developer Plus
Magento 2 Professional Developer
Magento 2 Solution Specialist