Skip to content

Instantly share code, notes, and snippets.

@rhoerr
Last active May 20, 2025 14:21
Show Gist options
  • Save rhoerr/a55285c9cabad6b87d592d5db7589262 to your computer and use it in GitHub Desktop.
Save rhoerr/a55285c9cabad6b87d592d5db7589262 to your computer and use it in GitHub Desktop.
MySQL views to aggregate Magento 2 EAV data -- requires MySQL 5.7+ or equivalent
/**
* Create aggregated SQL views for default EAV entity types in Magento:
* - dev_category
* - dev_product
* - dev_customer
* - dev_address
*
* Each view has the primary entity table, plus associated EAV values (eav_int, eav_text, etc).
* This is meant as a development tool to quickly see or select scoped data for a given entity.
* Do not use these for any runtime code, and be careful about how many rows you fetch at once.
*/
CREATE OR REPLACE VIEW dev_category AS
WITH cce_decimal AS (
SELECT cced.entity_id,
json_objectagg(if(cced.store_id>0, concat(ead.attribute_code, ':', cced.store_id), ead.attribute_code), cced.value) AS eav_decimal
FROM catalog_category_entity_decimal cced
INNER JOIN eav_attribute ead ON ead.attribute_id = cced.attribute_id
GROUP BY cced.entity_id
ORDER BY ead.attribute_code asc, cced.store_id asc
),
cce_datetime AS (
SELECT ccedate.entity_id,
json_objectagg(if(ccedate.store_id>0, concat(eadate.attribute_code, ':', ccedate.store_id), eadate.attribute_code), ccedate.value) AS eav_datetime
FROM catalog_category_entity_datetime ccedate
INNER JOIN eav_attribute eadate ON eadate.attribute_id = ccedate.attribute_id
GROUP BY ccedate.entity_id
ORDER BY eadate.attribute_code asc, ccedate.store_id asc
),
cce_int AS (
SELECT ccei.entity_id,
json_objectagg(if(ccei.store_id>0, concat(eai.attribute_code, ':', ccei.store_id), eai.attribute_code), ccei.value) AS eav_int
FROM catalog_category_entity_int ccei
INNER JOIN eav_attribute eai ON eai.attribute_id = ccei.attribute_id
GROUP BY ccei.entity_id
ORDER BY eai.attribute_code asc, ccei.store_id asc
),
cce_text AS (
SELECT ccet.entity_id,
json_objectagg(if(ccet.store_id>0, concat(eat.attribute_code, ':', ccet.store_id), eat.attribute_code), ccet.value) AS eav_text
FROM catalog_category_entity_text ccet
INNER JOIN eav_attribute eat ON eat.attribute_id = ccet.attribute_id
GROUP BY ccet.entity_id
ORDER BY eat.attribute_code asc, ccet.store_id asc
),
cce_varchar AS (
SELECT ccev.entity_id,
json_objectagg(if(ccev.store_id>0, concat(eav.attribute_code, ':', ccev.store_id), eav.attribute_code), ccev.value) AS eav_varchar
FROM catalog_category_entity_varchar ccev
INNER JOIN eav_attribute eav ON eav.attribute_id = ccev.attribute_id
GROUP BY ccev.entity_id
ORDER BY eav.attribute_code asc, ccev.store_id asc
)
SELECT cce.*,
COALESCE(cd.eav_decimal, '[]') AS eav_decimal,
COALESCE(cdt.eav_datetime, '[]') AS eav_datetime,
COALESCE(ci.eav_int, '[]') AS eav_int,
COALESCE(ct.eav_text, '[]') AS eav_text,
COALESCE(cv.eav_varchar, '[]') AS eav_varchar
FROM catalog_category_entity cce
LEFT JOIN cce_decimal cd ON cd.entity_id = cce.entity_id
LEFT JOIN cce_datetime cdt ON cdt.entity_id = cce.entity_id
LEFT JOIN cce_int ci ON ci.entity_id = cce.entity_id
LEFT JOIN cce_text ct ON ct.entity_id = cce.entity_id
LEFT JOIN cce_varchar cv ON cv.entity_id = cce.entity_id;
CREATE OR REPLACE VIEW dev_product AS
WITH cte_decimal AS (
SELECT cped.entity_id,
json_objectagg(if(cped.store_id>0, concat(ead.attribute_code, ':', cped.store_id), ead.attribute_code), cped.value) AS eav_decimal
FROM catalog_product_entity_decimal cped
INNER JOIN eav_attribute ead ON ead.attribute_id = cped.attribute_id
GROUP BY cped.entity_id
ORDER BY ead.attribute_code asc, cped.store_id asc
),
cte_datetime AS (
SELECT cpedate.entity_id,
json_objectagg(if(cpedate.store_id>0, concat(eadate.attribute_code, ':', cpedate.store_id), eadate.attribute_code), cpedate.value) AS eav_datetime
FROM catalog_product_entity_datetime cpedate
INNER JOIN eav_attribute eadate ON eadate.attribute_id = cpedate.attribute_id
GROUP BY cpedate.entity_id
ORDER BY eadate.attribute_code asc, cpedate.store_id asc
),
cte_int AS (
SELECT cpei.entity_id,
json_objectagg(if(cpei.store_id>0, concat(eai.attribute_code, ':', cpei.store_id), eai.attribute_code), cpei.value) AS eav_int
FROM catalog_product_entity_int cpei
INNER JOIN eav_attribute eai ON eai.attribute_id = cpei.attribute_id
GROUP BY cpei.entity_id
ORDER BY eai.attribute_code asc, cpei.store_id asc
),
cte_text AS (
SELECT cpet.entity_id,
json_objectagg(if(cpet.store_id>0, concat(eat.attribute_code, ':', cpet.store_id), eat.attribute_code), cpet.value) AS eav_text
FROM catalog_product_entity_text cpet
INNER JOIN eav_attribute eat ON eat.attribute_id = cpet.attribute_id
GROUP BY cpet.entity_id
ORDER BY eat.attribute_code asc, cpet.store_id asc
),
cte_varchar AS (
SELECT cpev.entity_id,
json_objectagg(if(cpev.store_id>0, concat(eav.attribute_code, ':', cpev.store_id), eav.attribute_code), cpev.value) AS eav_varchar
FROM catalog_product_entity_varchar cpev
INNER JOIN eav_attribute eav ON eav.attribute_id = cpev.attribute_id
GROUP BY cpev.entity_id
ORDER BY eav.attribute_code asc, cpev.store_id asc
)
SELECT cpe.*,
COALESCE(cd.eav_decimal, '[]') AS eav_decimal,
COALESCE(cdt.eav_datetime, '[]') AS eav_datetime,
COALESCE(ci.eav_int, '[]') AS eav_int,
COALESCE(ct.eav_text, '[]') AS eav_text,
COALESCE(cv.eav_varchar, '[]') AS eav_varchar
FROM catalog_product_entity cpe
LEFT JOIN cte_decimal cd ON cd.entity_id = cpe.entity_id
LEFT JOIN cte_datetime cdt ON cdt.entity_id = cpe.entity_id
LEFT JOIN cte_int ci ON ci.entity_id = cpe.entity_id
LEFT JOIN cte_text ct ON ct.entity_id = cpe.entity_id
LEFT JOIN cte_varchar cv ON cv.entity_id = cpe.entity_id;
CREATE OR REPLACE VIEW dev_customer AS
WITH cust_decimal AS (
SELECT custd.entity_id,
json_objectagg(ead.attribute_code, custd.value) AS eav_decimal
FROM customer_entity_decimal custd
INNER JOIN eav_attribute ead ON ead.attribute_id = custd.attribute_id
GROUP BY custd.entity_id
ORDER BY ead.attribute_code asc
),
cust_datetime AS (
SELECT custdate.entity_id,
json_objectagg(eadate.attribute_code, custdate.value) AS eav_datetime
FROM customer_entity_datetime custdate
INNER JOIN eav_attribute eadate ON eadate.attribute_id = custdate.attribute_id
GROUP BY custdate.entity_id
ORDER BY eadate.attribute_code asc
),
cust_int AS (
SELECT custi.entity_id,
json_objectagg(eai.attribute_code, custi.value) AS eav_int
FROM customer_entity_int custi
INNER JOIN eav_attribute eai ON eai.attribute_id = custi.attribute_id
GROUP BY custi.entity_id
ORDER BY eai.attribute_code asc
),
cust_text AS (
SELECT custt.entity_id,
json_objectagg(eat.attribute_code, custt.value) AS eav_text
FROM customer_entity_text custt
INNER JOIN eav_attribute eat ON eat.attribute_id = custt.attribute_id
GROUP BY custt.entity_id
ORDER BY eat.attribute_code asc
),
cust_varchar AS (
SELECT custv.entity_id,
json_objectagg(eav.attribute_code, custv.value) AS eav_varchar
FROM customer_entity_varchar custv
INNER JOIN eav_attribute eav ON eav.attribute_id = custv.attribute_id
GROUP BY custv.entity_id
ORDER BY eav.attribute_code asc
)
SELECT cust.*,
COALESCE(cd.eav_decimal, '[]') AS eav_decimal,
COALESCE(cdt.eav_datetime, '[]') AS eav_datetime,
COALESCE(ci.eav_int, '[]') AS eav_int,
COALESCE(ct.eav_text, '[]') AS eav_text,
COALESCE(cv.eav_varchar, '[]') AS eav_varchar
FROM customer_entity cust
LEFT JOIN cust_decimal cd ON cd.entity_id = cust.entity_id
LEFT JOIN cust_datetime cdt ON cdt.entity_id = cust.entity_id
LEFT JOIN cust_int ci ON ci.entity_id = cust.entity_id
LEFT JOIN cust_text ct ON ct.entity_id = cust.entity_id
LEFT JOIN cust_varchar cv ON cv.entity_id = cust.entity_id;
CREATE OR REPLACE VIEW dev_address AS
WITH addr_decimal AS (
SELECT caed.entity_id,
json_objectagg(ead.attribute_code, caed.value) AS eav_decimal
FROM customer_address_entity_decimal caed
INNER JOIN eav_attribute ead ON ead.attribute_id = caed.attribute_id
GROUP BY caed.entity_id
ORDER BY ead.attribute_code asc
),
addr_datetime AS (
SELECT caedate.entity_id,
json_objectagg(eadate.attribute_code,caedate.value) AS eav_datetime
FROM customer_address_entity_datetime caedate
INNER JOIN eav_attribute eadate ON eadate.attribute_id = caedate.attribute_id
GROUP BY caedate.entity_id
ORDER BY eadate.attribute_code asc
),
addr_int AS (
SELECT caei.entity_id,
json_objectagg(eai.attribute_code,caei.value) AS eav_int
FROM customer_address_entity_int caei
INNER JOIN eav_attribute eai ON eai.attribute_id = caei.attribute_id
GROUP BY caei.entity_id
ORDER BY eai.attribute_code asc
),
addr_text AS (
SELECT caet.entity_id,
json_objectagg(eat.attribute_code,caet.value) AS eav_text
FROM customer_address_entity_text caet
INNER JOIN eav_attribute eat ON eat.attribute_id = caet.attribute_id
GROUP BY caet.entity_id
ORDER BY eat.attribute_code asc
),
addr_varchar AS (
SELECT caev.entity_id,
json_objectagg(eav.attribute_code, caev.value) AS eav_varchar
FROM customer_address_entity_varchar caev
INNER JOIN eav_attribute eav ON eav.attribute_id = caev.attribute_id
GROUP BY caev.entity_id
ORDER BY eav.attribute_code asc
)
SELECT cae.*,
COALESCE(cd.eav_decimal, '[]') AS eav_decimal,
COALESCE(cdt.eav_datetime, '[]') AS eav_datetime,
COALESCE(ci.eav_int, '[]') AS eav_int,
COALESCE(ct.eav_text, '[]') AS eav_text,
COALESCE(cv.eav_varchar, '[]') AS eav_varchar
FROM customer_address_entity cae
LEFT JOIN addr_decimal cd ON cd.entity_id = cae.entity_id
LEFT JOIN addr_datetime cdt ON cdt.entity_id = cae.entity_id
LEFT JOIN addr_int ci ON ci.entity_id = cae.entity_id
LEFT JOIN addr_text ct ON ct.entity_id = cae.entity_id
LEFT JOIN addr_varchar cv ON cv.entity_id = cae.entity_id;
@rhoerr
Copy link
Author

rhoerr commented May 9, 2025

These queries/views aggregate all EAV values for each entity into a JSON column (eav_int, eav_text, etc) for easier debugging. For scoped entities, any scope values will be appended as "{attribute_code}:{store_id}"="{value}".

Don't use these for anything in runtime code. Be careful about how much data you select at once, if you have a large site.

I covered products, categories, customers, and addresses at this point. May put them into a composer-installable module if people would find it valuable.

You can use JSON functions on the EAV columns, for example:

SELECT *
FROM `dev_category`
WHERE JSON_EXTRACT(eav_int, "$.include_in_menu")=0;

Or:

SELECT
    entity_id,
    sku,
    JSON_EXTRACT(eav_varchar, "$.name") as name,
    JSON_EXTRACT(eav_decimal, "$.price") as price,
    eav_varchar
FROM `dev_product`
ORDER BY sku ASC
LIMIT 30

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment