Direct SQL Queries In Magento

piaoling  2011-06-21 17:53:32

Magento's use of data models provide a great way to access and modify data. Using aptly named methods and clever abstraction, Varien hide away the complex SQL needed to perform data operations. While this makes learning models easier, it often impacts the speed of the operation and therefore the responsiveness of your site. This is especially true when saving models that use the EAV architecture. More often that not, this cannot be avoided, however there are some situations where executing direct SQL queries would be simpler and much quicker. An example of this is updating product prices globally in Magento. It would be easy enough to write some Magento code that looped through all products and modified the price. On a large data set, saving each individual product can take a long time and therefore make the system unusable. To combat this, it is possible to issue a direct SQL query which could update 1000's of products in 1 or 2 seconds.

Database Connections In Magento

By default, Magento will automatically connect to it's database and provide two separate resources which you can use to access data: core_read and core_write. As you can probably guess, core_read is for reading from the database while core_write is for writing to the database. It is important to ensure that you use the correct resource when reading or writing data to the database, especially when writing custom Magento extensions that will be released into the wild.

Table names and table prefixes

When installing Magento, you are given the option to use a table prefix. A table prefix is a string of characters that is added to the start of every table name in your database. These are useful if you are installing multiple system into 1 database as it helps to distinguish each application's data from another. Fortunately, Magento has a simple built in function which allows you to add the prefix to a given table name.

?
1
2
3
4
5
6
7
8
9
<?php
$resource = Mage::getSingleton('core/resource');
$tableName = $resource->getTableName('catalog_product_entity');
 
/**
  * if prefix was 'mage_' then the below statement
  * would print out mage_catalog_product_entity
  */
echo $tableName;

Accessing the database connection resource

?
1
2
3
4
<?php
 
$read = Mage::getSingleton('core/resource')->getConnection('core_read');
$write = Mage::getSingleton('core/resource')->getConnection('core_write');

The getConnection() function takes the name of the resource you're trying to request as a parameter and returns an object of Varien_Db_Adapter_Pdo_Mysql. The class extends from Zend_Db_Adapter_Abstract and therefore you allows you to perform all Zend DB Adapter's functions on it.

For a list of functions available, copy the following code into a Magento template.

?
1
2
3
4
5
6
7
8
9
10
<?php
 
$read = Mage::getSingleton('core/resource')->getConnection('core_read');
 
echo '<pre>';
print_r(get_class_methods($read));
echo '</pre>';
exit;
 
?>

This should produce a list of available functions and will help illustrate just exactly what you can do using this object.

Reading data from the database

?
1
2
3
4
5
6
7
<?php
 
$read = Mage::getSingleton('core/resource')->getConnection('core_read');
$query = 'SELECT * FROM ' . Mage::getSingleton('core/resource')->getTableName('catalog_product_entity');
$results = $read->fetchAll($query);
 
print_r($results);

If you have any products in your Magento store, the above code will print out data corresponding to the core product entities. Try modifying the query to access other pieces of data.

Writing information to the database

?
1
2
3
4
5
6
7
8
9
<?php
 
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
 
// Add your own query below
// I didn't add one as I didn't want you to run the code
// and me break your database!
$query = 'add your query here';
$write->query($query);

Add your own query into the query variable above and run the code. If your query is valid SQL then it should be executed correctly and data changed however your query instructed.

Conclusion

Sometimes it is necessary to execute direct SQL queries in Magento, however, please be careful! The Magento model's are there for a reason and provide a layer of security which you will have to manually add to your own direct SQL queries. Be sure to escape any user input and when possible, stick to the Magento model methods!

As a side note, if you're going to be querying the database directly, it would be a good idea to learn about Magento's EAV database architecture. For more information on this, see the following link:

Magento Database Structure: EAV

This post was posted in General

12 Responses to Direct SQL Queries In Magento

Pete says:

Thanks for your article. I have been trying to find an educated answer to whether it ist safe to change product titles, descriptions, rewritable URL directly in the DB using SQL queries. from what I can see (but I am no expert) the magento catalog_product_entity_varchar and catalog_product_entity_text tables contain simple text fields (value) containing product descriptions, URLs and titles. I want to make SEO updates to my products replacing text strings within these tables with a query like

UPDATE catalog_product_entity_varchar SET value = replace(value, "OLD TITLE", "NEW TITLE");

After refreshing caches this seems to work ok, but I want to be sure there are no relational tables that will be impacted by changing these product, title, descriptions and URLs directly in the DB before I update 1000s of products!

Perhaps you can give me your thoughts.

类别 :  magento(258)  |  浏览(4040)  |  评论(3)
发表评论(评论将通过邮件发给作者):

Email:
userhead
2011-11-26 01:11:45
good article ;) thanks ! if you are interested in learning how to create a custom magento module wich interact with the database you can look at http://www.about-magento.com/magento-model-database-tutorial-54 and go deeper in magento ;) I hope to talk with you soon, Pierre.
userhead
侯会亮
2011-06-21 18:30:56
Since one of the things I keep hearing is the need for pricing output within a reasonable time frame for larger sites, here's a base price report using SQL queries. 9k in less than 30 seconds! [code]setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); $userModel = Mage::getModel('admin/user'); $userModel->setUserId(0); /* Set variables, since in EAV the entity and attribute id are sequential and uniquely assigned, * you'll need to look them up in the eav_attribute table for your magento installation to make * sure you have the right value */ $read = Mage::getSingleton('core/resource')->getConnection('core_read'); $pEntity = Mage::getSingleton('core/resource')->getTableName('catalog_product_entity'); $pVarchar = Mage::getSingleton('core/resource')->getTableName('catalog_product_entity_varchar'); $pDecimal = Mage::getSingleton('core/resource')->getTableName('catalog_product_entity_decimal'); $nameAttrId = 56; $priceAttrId = 60; /* SQL query to get base prices on simple product for store 0 */ $query = 'SELECT p_entity.sku AS sku, p_varchar.value AS name, p_decimal.value AS price FROM ' . $pEntity . ' p_entity, ' . $pDecimal . ' p_decimal, ' . $pVarchar . ' p_varchar WHERE p_entity.entity_id = p_varchar.entity_id AND p_entity.entity_id = p_decimal.entity_id AND ((p_entity.type_id="simple") AND (p_varchar.attribute_id=' . $nameAttrId . ') AND (p_varchar.store_id=0) AND (p_decimal.attribute_id=' . $priceAttrId . ') AND (p_decimal.store_id=0))'; $results = $read->fetchAll($query); /* straight dump to screen without formatting */ print_r($results); ?>[/code]
userhead
侯会亮
2011-06-21 17:54:07
To list the functions, the code had to be modified to: [code]setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); $userModel = Mage::getModel('admin/user'); $userModel->setUserId(0); $read = Mage::getSingleton('core/resource')->getConnection('core_read'); echo '
';
print_r(get_class_methods($read));
echo '
'; exit; ?> [/code]