Is there a way by mysql to set ALL product visibility to catalog, search?
open up the eav_attribute table and find the row where attribute_code = visibility. Take note of the attribute_id, most likely it will be 85. Also take note that backend_type = int. This tells you that the attribute is stored in catalog_product_entity_int. So, now you can run:
update `catalog_product_entity_int` set value = 4 where attribute_id = 85
(assuming of course that the attribute_id was 85!)
Make sure you backup the database before you run it.
HTH,
JD
Related
working on resolving issue where we need to update several thousand rows where there is an admin entity that isnt verified yet but there is a matching admin entity name in the verified list.
i have script written to pull the rows from that joins together the 2 tables. this gives me the list of rows that need update.
SELECT
pi.id AS `Primary Key for PI`,
pi.admin_entity_id,
pi.admin_entity_unverified,
asa.id AS `Admin Setup Accounts ID`,
asa.name AS `Admin Entity-Verified`
FROM
p_information pi
LEFT JOIN admin_setup_accounts asa ON asa.name =
pi.admin_entity_unverified
WHERE
pi.admin_entity_unverified IS NOT NULL
AND pi.admin_entity_unverified <> ''
AND pi.admin_entity_id IS NULL
AND pi.admin_entity_unverified IN (select name FROM
admin_setup_accounts)
http://sqlfiddle.com/#!9/a8c11a/3/0
This query returns list of unverified entries (pi.admin_entity_unverified) that match a verified list (asa.name) and the ID (asa.id) for each of those verified names.
i now need to do an update of all these matching rows and update the pi tables admin_entity_id with the corresponding admin setup accounts id (asa.id), so im thinking of doing like
update p_information pi
inner join (
SELECT
pi.id AS `Primary Key for PI`,
pi.admin_entity_id,
pi.admin_entity_unverified,
asa.id AS `Admin_Setup_ Accounts_ID`,
asa.name AS `Admin Auditing Entity-Verified`
FROM
p_information pi
LEFT JOIN admin_setup_accounts asa ON asa.name =
pi.admin_auditing_entity_unverified
WHERE
pi.admin_auditing_entity_unverified IS NOT NULL
AND pi.admin_auditing_entity_unverified <> ''
AND pi.admin_auditing_entity_id IS NULL
AND pi.admin_auditing_entity_unverified IN (select name FROM
admin_setup_accounts)) upi
ON upi.id = pi.id
SET pi.admin_entity_id = (this needs to be the asa.id AS `Admin Setup Accounts ID` returned from the subquery (upi)
but since pi and asa both use the id column inside the subquery how can i list those outside the query ? or is there another way to get this update done using the query? let me know
thanks
well i think i figured it out, i was thinking i couldnt use the column aliases outside the sub query, but it appears to work just fine. i do the set command as set pi.admin_entity_id = upi.Admin_Setup_ Accounts_ID and it updates correctly . :) oh well guess shouldnt overthink it
I've been reading through SO and other sites, and have followed a few examples; however, my SQL statments is still not performing as required.
I have two tables
parts
============================
pmkParts fnkManufacturer
----------------------------
0 Penn-Union
1 Schneider
2 Telemecanique
and
manufacturer
===============================
Manufacturer pmkManufacturer
-------------------------------
Penn-Union 45
Schneider 56
Telemecanique 12
I want to change the parts table into
parts
============================
pmkParts fnkManufacturer
----------------------------
0 45
1 56
2 12
Here is the SQL statement I tried.
Update parts
SET parts.fnkManufacturer = (
SELECT manufacturer.pmkManufacturer
FROM manufacturer
WHERE manufacturer.pmkManufacturer = parts.fnkManufacturer
)
That is changing the correct column, but it is filling it with 'NULLS' rather than the foreign key (manufacturer). I think there should be a join somewhere in there, but I'm not sure where.
Any tips?
----------
EDIT: Answer:
Here is the SQL statement that worked. Thanks MarcB for the help.
Update parts
SET parts.fnkManufacturer = (
SELECT manufacturer.pmkManufacturer
FROM manufacturer
WHERE manufacturer.Manufacturer= parts.fnkManufacturer
)
Try changing your query like below using a update join query. Again, you are joining on the wrong column, you actually should be joining to manufacturer.Manufacturer column rather.
Update parts p
JOIN manufacturer m ON m.Manufacturer = p.fnkManufacturer
SET p.fnkManufacturer = m.pmkManufacturer;
Your pmkManufacturer looks like int so it is better to add new int field to parts, update it and then remove old column. Something like this.
alter table dbo.parts add pmkManufacturer int
update dbo.parts
set pmkManufacturer = m.pmkManufacturer
from dbo.parts p
inner join dbo.Manufacturer m on p.fnkManufacturer = m.manufacturer
The best solution, you could use INNER JOIN, I for example :
update parts p
inner join manufacturer m on
p.pmkManufacturer = m.Manufacturer
set p.pmkManufacturer = m.pmkManufacturer
Howerver, in your case, if I was wrong, you want to update pmkManufacturer while pmkManufacturer is actually the condition ON for INNER JOIN so I'm not sure that it'okay for request. If not, it isn't also difficult, you could add a new column : pmk_bis_manufacturer and set the value into this column, then delete the old column pmkManufacturer and change the name of new column if nescessary.
One tip for you : the name of columns database, I prefer setting :
pmk_manufacturer instead of pmkManufacturer because capital letter in the name
could make one problem in the futur. For example : for ORM Doctrine,
it isn't good :D
First of all, I know I should be using the model rather than working on the database directly. That being said, does anyone know exactly how Magento handles non-global product attributes?
I have 2 websites in core_website: Admin (website_id = 0) and Main Website (website_id =1). I also have two stores in core_store: Admin (store_id = 0) and Default Store View (store_id = 0). It seems that whether or not a product (or category?) attribute is global in scope is stored in catalog_eav_attribute.is_global. A value of 0 corresponds to a scope of "Store View," a value of 1 corresponds to "Global," and 2 corresponds to "Website." So far so good.
Now, if I wanted to get the value of a store-specific attribute like "name" (eav_attribute.attribute_id = 71; eav_attribute.backend_type = 'varchar'; catalog_eav_attribute.is_global = 0) for all my products, you would think I would do something like this:
SELECT *
FROM catalog_product_entity_varchar
WHERE attribute_id = 71
AND store_id = 1
But that returns nothing. All of the names are actually in rows with store_id = 0. As far as I can tell the only attributes in the database that are stored with store_id = 1 are 'url_key' and 'url_path'. So how does Magento store these values? And how does Magento retrieve them?
Are all values initially(or also) stored with store_id = 0 as a kind of default, until a different value than that one needs to be stored? When a store-specific value that is different from the admin value needs to be stored, does magento then create a new row with store_id = 1 (or whatever store_id it is)?
If that - or something like that - is the case, then how does Magento retrieve store-specific values? Does it check catalog_eav_attribute.is_global first for the attribute in question? If it is non-global, it could then first query with store_id = 1, and if that returns nothing, then query with the default store_id = 0?
I guess my main question is how does magento actually do it. Secondarily, why does magento do it this way instead of storing values with the actual store_id? Also, if I were to write a query, should I query both store_id = 0 and store_id = 1 and choose the right value based on whether or not the attribute is global and whether or not there is a value present for store_id = 1?
You seem to have it figured out. At least you have a good idea on how things are done.
To summarize and confirm your suspicions:
All the attribute values are stored in catalog_product_entity_* where * can be anyone of theses: decimal, int, varchar, text, datetime depending on the attribute type (backend_type).
There are also other tables that keep the data related to tier pricing and images but let's leave that for now.
Attribute table definition
Each of the tables have the following columns:
value_id - just an increment id for the table
entity_type_id - the entity type id for the product (always the same)
attribute_id - reference to the attribute
store_id - reference to the store view
entity_id - reference to the product
value - actual value
There is a unique constraint on these columns entity_id,attribute_id,store_id. This means that for one product and one attribute you can have only one value for a store view.
Now the part where you are right.
store_id = 0 means that the value stored there is a default value.
If there is no value specified for a specific store view (store_id >= 1) then this value will be used.
If the attribute is set as global then the value for store_id = 0 will be used even if you have values for store_id = 1.
Examples
To get an idea of how the values are retrieved put this code in some file and run it (make sure the flat catalog is disabled - more on that later, and make sure you created an instance of the application first using Mage::app()):
Store view attribute
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('name', 'some_name');
echo $collection->getSelect();
The code above means that I want to retrieve a list of products with the name some_name.
the sql query associated to the collection looks like this:
SELECT
`e`.*,
IF(at_name.value_id > 0, at_name.value, at_name_default.value) AS `name`
FROM
`catalog_product_entity` AS `e`
INNER JOIN
`catalog_product_entity_varchar` AS `at_name_default`
ON (`at_name_default`.`entity_id` = `e`.`entity_id`) AND
(`at_name_default`.`attribute_id` = '96') AND
`at_name_default`.`store_id` = 0
LEFT JOIN
`catalog_product_entity_varchar` AS `at_name`
ON (`at_name`.`entity_id` = `e`.`entity_id`) AND
(`at_name`.`attribute_id` = '96') AND
(`at_name`.`store_id` = 1)
WHERE
(IF(at_name.value_id > 0, at_name.value, at_name_default.value) = 'some_name')
Ugly huh?
Because the name attribute (id 96 in my case) is a store view scope attribute (is_global = 0) Magento joins twice with the table catalog_product_entity_varchar (the one that holds the name), once for the current store view and once for the detault store view (id = 0). adding a condition:
IF(at_name.value_id > 0, at_name.value, at_name_default.value)
So if there is no value for the store id 1, use the default value.
Global attribtue
Now let's see what happens if we filter by a global attribute.
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('weight', '1');
echo $collection->getSelect();
The sql printed looks like this:
SELECT
`e`.*,
`at_weight`.`value` AS `weight`
FROM
`catalog_product_entity` AS `e`
INNER JOIN
`catalog_product_entity_decimal` AS `at_weight`
ON (`at_weight`.`entity_id` = `e`.`entity_id`) AND
(`at_weight`.`attribute_id` = '101') AND
(`at_weight`.`store_id` = 0)
WHERE
(at_weight.value = '1')
So one single join with the table catalog_product_entity_decimal for the store id = 0.
Website attribute
If the scope of the attribute is website everything happens just like it does for the store view scope, because Magento creates a line in the attribute values table for each store view in the current website when saving the product.
If you want to try it use the attribute status in the examples above.
Flat Catalog
I promised earlier some explanations about "flat catalog".
For performance reasons Magneto introduced this feature (I don't remember the version).
Basically a cron runs (or you can run it by hand) and transforms the EAV approach for the products and categories into flat tables. One for each store view you have (except store id = 0).
This means one attribute will be transformed into one column in the new table. The new table is called catalog_product_flat_{store_view_id_here}.
This avoids the numerous left/inner joins when wanting the values for some attributes.
but again, for performance reasons, not all the attributes are added as columns in the flat tables (for products only. For categories all of them are added).
Only the attributes marked in the backend with Use in product listing are transformed into columns.
You can turn on/off this feature from System->Configuration->Catalog->Frontend->Use Flat Catalog Product (or Use Flat Catalog Category).
Even if turned on, the flat tables are used only in the frontend. The backend still uses the EAV approach.
Conclusion
My conclusion is that it is almost impossible to write your own queries to retrieve data directly from the DB. You should use the models and collections that magento provides. It saves a lot of mental health.
I hope I made things a little clearer for you.
I am trying to figure out how to update a row in one table, setting a column value equal to a value in a different table. Here's an example:
movies:
movie_id | movie_price
movies_attended:
attended_id | attended_movie_id | attended_movie_price
Now, this is kind of a stupid example, but supposed that for some reason there is a row in movies_attended that does not have the correct attended_movies_price in it and so it needs to be updated.
How should a query be written to update the movies_attended table, setting movies_attended.attended_movie_price = movies.movie_price?
I tried something similar to the following, but it did not work:
update movies_attended, movies
set movies_attended.attended_movie_price = movies.movie_price
where movies_attended.attended_movie_id = movies.movie_id
AND attended_id = [the id of the row we want to update]
When you say "it did not work", do you mean that it reported 0 rows updated, or did the statement cause the database raise an exception?
Your example statement appears to be of the form:
UPDATE movies_attended a
JOIN movies m
ON a.attended_movie_id = m.movie_id
SET a.attended_movie_price = m.movie_price
WHERE a.attended_id = ?
(We typically prefer the JOIN ... ON ... style syntax to the comma join operator and the join predicates in the WHERE clause.)
I have no explanation as to why this statement would "not work".
It's possible this would report 0 rows affected, if no rows satisfy the predicates. It would also report 0 rows affected if the rows that would be changed do not require any changes... that is, the existing value in attended_movie_price already matches the value being assigned to it.
Normally, before running an update statement like that, I write it as a SELECT first, and see what values are returned...
By replacing the UPDATE keyword with SELECT ... FROM, and removing the SET clause:
SELECT m.movie_price AS new_val
, a.attended_movie_price AS old_val
, a.attended_id
FROM UPDATE movies_attended a
JOIN movies m
ON a.attended_movie_id = m.movie_id
WHERE a.attended_id = ?
This is actually a bad database design. You don't need movie price in two tables.
But, if you just need this, it goes something along this:
UPDATE movies_attended
INNER JOIN
movies
ON movies_attended.attended_movie_id = movies.movie_id
SET movies_attended.attended_movie_price = movie.movie_price
i'm facing a big problem when trying to update a table containing stock data put in join with a table containing product classification. This operation is taking long time for execution.
Table dw_giacenze (having flag_nomatch parameter equal to T) a is put on inner join with dw_key_prod z on ecat_key field.
a contains up to 3 milions records, z 150k records.
It takes more than 2 hours in execution.
Below the update query I'm using.
update dw_giacenze
set cate_ecat_key = z.cate_ecat_key,
sottocat_ecat_key = z.sottocat_ecat_key,
marchio_key = z.marchio_key,
sottocat_bi_key = z.sottocat_bi_key,
gruppo_bi_key = z.gruppo_bi_key,
famiglia_bi_key = z.famiglia_bi_key,
flag_nomatch = NULL
from dw_giacenze a
inner join dw_key_prod z on
z.ecat_key = a.ecat_key
where
a.flag_nomatch = 'T';
Can anyone help me in optimizing it?
Thanks in advance!
Enrico
I would suggest focusing in on a.flag_nomatch = 'T'.
A great way to get a really clear picture of what's going on is to use SQL Server Profiler. If this shows that your reads equals the number of rows in the table, then that's definitely an issue. Adding an index on flag_nomatch.
Alternatively, you could separate this out and update things individually (to start with)
UPDATE dw_giacenze
set sottocat_ecat_key = (SELECT sottocat_ecat_key
FROM dw_key_prod
WHERE dw_key_prod.ecat_key = dw_giacenze.ecat_key)
where
dw_giacenze.flag_nomatch = 'T';
I did notice that the first parameter in your set statement is actually the same parameter in your join. That means that you are setting it to the same exact value, so you should be able to remove that anyway.