What is the best optimization for this table and its queries? - mysql

I have this table:
CREATE TABLE IF NOT EXISTS `listings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` tinyint(1) NOT NULL DEFAULT '1',
`hash` char(32) NOT NULL,
`source_id` int(10) unsigned NOT NULL,
`link` varchar(255) NOT NULL,
`short_link` varchar(255) NOT NULL,
`cat_id` mediumint(5) NOT NULL,
`title` mediumtext NOT NULL,
`description` mediumtext,
`content` mediumtext,
`images` mediumtext,
`videos` mediumtext,
`views` int(10) NOT NULL,
`comments` int(11) NOT NULL DEFAULT '0',
`comments_update` int(11) NOT NULL DEFAULT '0',
`editor_id` int(11) NOT NULL DEFAULT '0',
`auther_name` varchar(255) DEFAULT NULL,
`createdby_id` int(10) NOT NULL,
`createdon` int(20) NOT NULL,
`editedby_id` int(10) NOT NULL,
`editedon` int(20) NOT NULL,
`deleted` tinyint(1) NOT NULL,
`deletedon` int(20) NOT NULL,
`deletedby_id` int(10) NOT NULL,
`deletedfor` varchar(255) NOT NULL,
`published` tinyint(1) NOT NULL DEFAULT '1',
`publishedon` int(20) NOT NULL,
`publishedby_id` int(10) NOT NULL,
PRIMARY KEY (`id`),
KEY `hash` (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT AUTO_INCREMENT=91628 ;
and some bad queries like this
SELECT id,type , source_id, link, short_link, cat_id, title,
description, images, views, comments, published, publishedon,
content, comments_update, editor_id, auther_name, createdby_id,
createdon, editedby_id, editedon, deleted, deletedon,
deletedby_id, deletedfor, publishedby_id
FROM listings
WHERE (cat_id IN ( 98 ))
AND (TYPE IN ('1'))
AND (source_id IN ('78'))AND (FROM_UNIXTIME( publishedon ) >= SUBDATE( NOW( ) ,
1 )
)
AND (deleted =0)
AND (published =1)
ORDER BY `publishedon` DESC
LIMIT 10 OFFSET 0
and
SELECT id,type,source_id,link,short_link,cat_id,title,description,
images,views,comments,published,publishedon
FROM listings
WHERE (title RLIKE 'اليمن|عدن')
AND (id != 89024)
AND (deleted = 0)
AND (published = 1)
ORDER BY publishedon DESC
LIMIT 6 OFFSET 0
and
SELECT MIN(id) FROM listings
WHERE (id > 91152) AND (cat_id = '134')
and
SELECT COUNT(id)
FROM listings
WHERE (publishedon >= '1442963362'
AND publishedon <= '1443568162'
)
AND (cat_id IN ('19', '20', '21', '22', '23', '24', '27',
'32', '35', '110', '54', '38', '39', '41', '42', '43',
'44', '45', '46', '47', '49', '56', '57', '51', '55',
'58', '59', '60', '61', '62', '102', '95', '96', '98',
'101', '103', '104', '105', '106', '124', '125', '130',
'131', '132', '133', '134', '135')
)
this query may takes 0.4 sec to be done. Any in one page it may contain 5 queries like this. This is very big problem; it causes server load and down time.
This query
SELECT *
FROM `listings`
WHERE id = 5455
takes 0.0004 sec to be done because its depend on the index of pk
How can I make indexes for columns in the first query?
And many times when I use "show processlist", I see this "Waiting for table level lock" too much and "sorting data".
The application insert/update many rows all the times; how can I solve this?

Your query is basically:
SELECT . . .
FROM listings l
WHERE cat_id = 98 AND
TYPE = 1 AND
source_id = 78 AND
deleted = 0 AND
published = 1 AND
FROM_UNIXTIME( publishedon ) >= SUBDATE( NOW( ) , 1 )
ORDER BY `publishedon` DESC
LIMIT 10
OFFSET 0
For performance, start with a composite index on (cat_id, type, source_id, deleted, published, publishedon). The syntax is:
create index idx_listings_6 on listings(cat_id, type, source_id, deleted, published, publishedon desc);
Next, I would suggest re-writing the where clause as:
SELECT . . .
FROM listings l
WHERE cat_id = 98 AND
TYPE = 1 AND
source_id = 78 AND
deleted = 0 AND
published = 1 AND
publishedon >= UNIX_TIMESTAMP(SUBDATE( NOW( ) , 1 ))
ORDER BY `publishedon` DESC
LIMIT 10
OFFSET 0
And use the same index above.

MySQL cannot declare an index to be DESC; it ignores that keyword and builds an ASC index. However, ORDER BY x DESC is still optimizable.
MySQL will use only one INDEX per SELECT. (Usually).
The optimal index starts with any WHERE clause fields with '='.
Query 1: Already discussed.
Query 2: INDEX(deleted, published, publishedon)
Query 3: INDEX(cat_id, id)
Query 4: Change COUNT(id) to COUNT(*) and add either INDEX(cat_id, publishedon) and/or INDEX(publishedon, cat_id). It is not obvious which index would be better. Add both and let the optimizer decide. As in your other question, it may be beneficial to PARTITION BY RANGE(publishedon) and use INDEX(cat_id, publishedon) (not the other one).
Consider switching to InnoDB.

Related

Sql query - Cant select the max value of a row

I have this query that showing items in my site.
$sql = "
select p.id
, p.name
, p.logo
, p.short_description
, c.Parent_category
, IF(d.commission_name = 'percent'
, CONCAT(FORMAT(d.action, 2)/2 ,' %')
, CONCAT(FORMAT(d.action,2)/2,' €')) as comms
, GROUP_CONCAT(c.category_name SEPARATOR ',') as category_names
from eshop p
join eshop_cat c
on p.id = c.eshop_id
join eshop_commissions d
on p.id = d.eshop_id
where c.Parent_category = 'fashion'
and p.sites = 1
GROUP
BY d.action DESC
";
The problem is here
IF(d.commission_name = 'percent', CONCAT(FORMAT(d.action, 2)/2 ,' %') ,
CONCAT(FORMAT(d.action,2)/2,' €'))
i need only the biggest value of each eshop id. i tryied with this
IF(d.commission_name = 'percent', CONCAT(FORMAT(max(d.action), 2)/2 ,' %') ,
CONCAT(FORMAT(max(d.action),2)/2,' €'))
but its not working
For example i have 2 entries with the same eshop id
How can i receive only 1 commission that will be the biggest?
eshop_id commission_name action
1 percent 20 (%)
1 fixed_amount 30 (euro)
EDITED
CREATE TABLE `eshop` (
`id` int(11) NOT NULL,
`name` text NOT NULL,
`logo` text NOT NULL,
`short_description` text NOT NULL,
`sites` tinyint(1) NOT NULL,
`url` text NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`summary` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `eshop_commissions` (
`commission_name` text NOT NULL,
`eshop_id` int(11) NOT NULL,
`action` decimal(10,2) NOT NULL,
`subaction` decimal(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `eshop_cat` (
`eshop_id` int(11) NOT NULL,
`category_name` text NOT NULL,
`Parent_category` text
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `eshop_commissions` (`commission_name`, `eshop_id`, `action`, `subaction`) VALUES
('percent', 100, '12.00', '12.00'),
('fixed_amount', 100, '15.00', '15.00'),
('percent', 100, '5.00', '5.00'),
('percent', 100, '2.00', '2.00');
INSERT INTO `eshop` (`id`, `name`, `logo`, `short_description`, `description`, `sites`, `url, `timestamp`, `summary`) VALUES
(100, 'Tokotoukan', 'logo-tokotoukan.gif', '<p>\r\n !</p>\r\n', '<p>\r\n <font face=\"arial\" size=\"2\">Τo TOKOTOUKAN </font></p>\r\n', 1, 'http://www.com', ''2017-07-07 17:39:59', '15,00%');
INSERT INTO `eshop_cat` (`eshop_id`, `category_name`, `Parent_category`) VALUES
(100, 'fashion', 'fashion');

MySQL Sub Query takes long time to respond

I've created 3 tables imei, post and view. I've some 1000 records in all the 3 tables. Now when I execute the b/m query, it tooks very long to respond.
Table design & sample data are given below:
CREATE TABLE IF NOT EXISTS `imei` (
`imei_id` int(5) NOT NULL AUTO_INCREMENT,
`imei_no` varchar(30) NOT NULL,
`imei_net` varchar(30) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`imei_id`),
UNIQUE KEY `imei_no` (`imei_no`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1346 ;
CREATE TABLE IF NOT EXISTS `post` (
`post_id` int(5) NOT NULL AUTO_INCREMENT,
`post_title` varchar(60) NOT NULL,
`post_desc` varchar(500) NOT NULL,
`post_author` varchar(30) NOT NULL DEFAULT 'Admin',
`user_id` int(10) NOT NULL DEFAULT '1',
`date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=876 ;
CREATE TABLE IF NOT EXISTS `view` (
`view_id` int(5) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`imei_id` varchar(30) NOT NULL,
`status` varchar(10) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`view_id`),
UNIQUE KEY `imei_id` (`imei_id`,`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=13706 ;
Values Inside table:
IMEI:
INSERT INTO `imei` (`imei_id`, `imei_no`, `imei_net`, `date`) VALUES
(1, '123456789012345', 'Airtel', '2015-08-06 07:39:47'),
(2, '234567890123456', 'Aircel', '2015-08-06 06:08:33')
POST:
INSERT INTO `post` (`post_id`, `post_title`, `post_desc`, `post_author`, `user_id`, `date`) VALUES
(1, 'NSC Rate Down', 'NSC rates are getting down from today', 'Admin', 1, '2015-07-08 05:29:54'),
(2, 'NCDEX offers cashback', 'NCDEX offers cashback for the previous users', 'Admin', 1, '2015-07-08 05:30:01')
VIEW:
INSERT INTO `view` (`view_id`, `post_id`, `imei_id`, `status`, `date`) VALUES
(1, 1, '1', '1', '2015-08-08 05:04:38'),
(7, 2, '1', '1', '2015-08-08 07:55:25')
Query to Execute:
SELECT
*
FROM
(
SELECT
i.imei_id,
i.imei_no,
p.post_id,
p.post_title,
p.post_desc,
p.date,
1 AS STATUS
FROM
imei i,
post p,
VIEW v
WHERE
i.imei_id = v.imei_id
AND p.post_id = v.post_id
AND i.imei_no = 356554064098771
UNION
SELECT
i.imei_id,
i.imei_no,
p.post_id,
p.post_title,
p.post_desc,
p.date,
0 AS STATUS
FROM
imei i,
post p
WHERE
i.imei_no = 356554064098771
AND p.post_id NOT IN (
SELECT
v.post_id
FROM
imei i,
post p,
VIEW v
WHERE
p.post_id = v.post_id
AND v.imei_id = (
SELECT
i.imei_id
FROM
imei i
WHERE
imei_no = 356554064098771
)
)
) AS temp
WHERE
date >= DATE_SUB(
(
SELECT
date
FROM
imei
WHERE
imei_no = 356554064098771
),
INTERVAL 1 WEEK
)
ORDER BY
date DESC
try this query SELECT post_id,post_title,post_desc,date,if((post_id in (SELECT post_id FROM view WHERE imei_id = (SELECT imei_id FROM imei WHERE imei_no=865645026396909))),1,0) as status FROM post

SQL query running extremely slow

I have an sql query that collects the year to date totals for all products in the inventory. This query runs quickly, returning around 5000 results in a little over a second.
The query used is
SELECT `ITINCODE` as Code, `IT_product_id` as ID,
SUM(IF(YEAR(`ITDATE`) = YEAR(CURDATE() ), IF(ITTYPE = "O",`ITVAL`, -`ITVAL` ), 0) ) as 'YTD_VAL'
FROM `FITEMS`
WHERE (ITTYPE = 'O' OR `ITTYPE` = 'R') AND ITBACKORDER = 'N' AND ITAMNT > 0 AND YEAR(`ITDATE`) >= YEAR(CURDATE() ) -1
GROUP BY `ITINCODE`
ORDER BY YTD_VAL DESC
I want to take the values in YTD_VAL and store them in the actual products table so that they can be used as an ORDER BY on other queries. I added a new field called ytd_val to the products table and then ran
UPDATE products p SET p.ytd_val =
(SELECT SUM(IF(YEAR(`ITDATE`) = YEAR(CURDATE() ), IF(ITTYPE = 'O',`ITVAL`, -`ITVAL` ), 0) ) as 'YTD_VAL'
FROM `FITEMS`
WHERE ITINCODE = p.products_model AND (ITTYPE = 'O' OR `ITTYPE` = 'R') AND ITBACKORDER = 'N' AND ITAMNT > 0 AND YEAR(`ITDATE`) >= YEAR(CURDATE() ) -1
GROUP BY `ITINCODE`
ORDER BY YTD_VAL DESC)
The idea was to run this by cron job each night so that the values were updated to reflect the previous days sales.
However, running this query has taken 10 plus minutes and it still hasn't completed.
ITINCODE in FITEMS table is the same as products_model in the products table.
IT_product_id in the FITEMS table is the same as products_id in the products table.
What can I do to speed up the query? I thought that as the original results query returns quickly enough that simply updating the values on another table would take seconds longer!
Table structure is as follows:
show create table fitems\G;
Create Table: CREATE TABLE `fitems` (
`ITUNIQUEREF` int(11) unsigned NOT NULL,
`ITAMNT` int(11) NOT NULL,
`ITREF` int(11) unsigned NOT NULL,
`ITTYPE` char(1) NOT NULL,
`ITVAL` decimal(10,4) NOT NULL,
`ITVAT` decimal(10,4) NOT NULL,
`ITPRICE` decimal(10,4) NOT NULL,
`ITDATE` date NOT NULL,
`ITBACKORDER` char(1) NOT NULL,
`ITDISC` decimal(10,2) NOT NULL,
`ITORDERREF` int(11) NOT NULL,
`ITTREF` int(11) unsigned NOT NULL,
`ITDATEDLY` date NOT NULL,
`ITINCODE` char(20) NOT NULL,
`IT_product_id` int(11) unsigned NOT NULL,
`ITBUILT` int(11) NOT NULL,
PRIMARY KEY (`ITUNIQUEREF`),
KEY `ITREF` (`ITREF`,`ITTYPE`,`ITDATE`,`ITBACKORDER`,`ITORDERREF`,`ITDATEDLY`,`ITINCODE`,`IT_product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
.
show create table products\G;
CREATE TABLE `products` (
`products_id` int(11) NOT NULL,
`products_type` int(11) NOT NULL DEFAULT '1',
`products_quantity` float NOT NULL DEFAULT '0',
`products_model` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
`products_image` varchar(64) CHARACTER SET utf8 DEFAULT NULL,
`products_price` decimal(15,4) NOT NULL DEFAULT '0.0000',
`products_group_a_price` decimal(15,4) NOT NULL,
`products_group_b_price` decimal(15,4) NOT NULL,
`products_group_c_price` decimal(15,4) NOT NULL,
`products_group_d_price` decimal(15,4) NOT NULL,
`products_group_e_price` decimal(15,4) NOT NULL,
`products_group_f_price` decimal(15,4) NOT NULL,
`products_group_g_price` decimal(15,4) NOT NULL,
`products_virtual` tinyint(1) NOT NULL DEFAULT '0',
`products_date_added` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
`products_last_modified` datetime DEFAULT NULL,
`products_date_available` datetime DEFAULT NULL,
`products_weight` float NOT NULL DEFAULT '0',
`products_status` tinyint(1) NOT NULL DEFAULT '0',
`products_tax_class_id` int(11) NOT NULL DEFAULT '0',
`manufacturers_id` int(11) DEFAULT NULL,
`products_ordered` float NOT NULL DEFAULT '0',
`products_quantity_order_min` float NOT NULL DEFAULT '1',
`products_quantity_order_units` float NOT NULL DEFAULT '1',
`products_priced_by_attribute` tinyint(1) NOT NULL DEFAULT '0',
`product_is_free` tinyint(1) NOT NULL DEFAULT '0',
`product_is_call` tinyint(1) NOT NULL DEFAULT '0',
`products_quantity_mixed` tinyint(1) NOT NULL DEFAULT '0',
`product_is_always_free_shipping` tinyint(1) NOT NULL DEFAULT '0',
`products_qty_box_status` tinyint(1) NOT NULL DEFAULT '1',
`products_quantity_order_max` float NOT NULL DEFAULT '0',
`products_sort_order` int(11) NOT NULL DEFAULT '0',
`products_canonical` text COLLATE utf8_unicode_ci NOT NULL,
`products_discount_type` tinyint(1) NOT NULL DEFAULT '0',
`products_discount_type_from` tinyint(1) NOT NULL DEFAULT '0',
`products_price_sorter` decimal(15,4) NOT NULL DEFAULT '0.0000',
`master_categories_id` int(11) NOT NULL DEFAULT '0',
`products_mixed_discount_quantity` tinyint(1) NOT NULL DEFAULT '1',
`metatags_title_status` tinyint(1) NOT NULL DEFAULT '0',
`metatags_products_name_status` tinyint(1) NOT NULL DEFAULT '0',
`metatags_model_status` tinyint(1) NOT NULL DEFAULT '0',
`metatags_price_status` tinyint(1) NOT NULL DEFAULT '0',
`metatags_title_tagline_status` tinyint(1) NOT NULL DEFAULT '0',
`pricing_group` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`ytd_val` int(20) NOT NULL,
PRIMARY KEY (`products_id`),
KEY `idx_products_date_added_zen` (`products_date_added`),
KEY `idx_products_status_zen` (`products_status`),
KEY `idx_products_date_available_zen` (`products_date_available`),
KEY `idx_products_ordered_zen` (`products_ordered`),
KEY `idx_products_model_zen` (`products_model`),
KEY `idx_products_price_sorter_zen` (`products_price_sorter`),
KEY `idx_master_categories_id_zen` (`master_categories_id`),
KEY `idx_products_sort_order_zen` (`products_sort_order`),
KEY `idx_manufacturers_id_zen` (`manufacturers_id`),
KEY `products_price` (`products_price`),
KEY `products_status_products_price` (`products_status`,`products_price`),
FULLTEXT KEY `idx_enhanced_products_model` (`products_model`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
SELECT is always way faster then UPDATE.
To speed up an update:
Look at the indexes on the table you are updating: Are they all needed? If not, remove unneeded ones (I would at least remove idx_products_status_zen since that is also covered by products_status_products_price)
Look at the data model: Can you partition the table you are updating? If so, that will speed up the update since the indexes you are updating will be smaller and thus quicker to update;
Use InnoDB. It is faster;
Do you need to be ACID compliant? If not, then change the settings of InnoDB to speed up the system.
If you are really using MySQL: Switch to MariaDB: It is about 8% faster;
Install monitoring to see where your bottleneck is: IO or CPU: If it is IO on read, then try compression.
If you are satisfied with first query performance.
You can just transform your second query to use INNER JOIN like:
http://sqlfiddle.com/#!9/1028a/1
UPDATE products p
INNER JOIN (
SELECT SUM(IF(YEAR(`ITDATE`) = YEAR(CURDATE() ), IF(ITTYPE = 'O',`ITVAL`, -`ITVAL` ), 0) ) as 'YTD_VAL',
ITINCODE
FROM `FITEMS`
WHERE (ITTYPE = 'O' OR `ITTYPE` = 'R')
AND ITBACKORDER = 'N' AND ITAMNT > 0 AND YEAR(`ITDATE`) >= YEAR(CURDATE() ) -1
GROUP BY `ITINCODE`
) t
ON t.ITINCODE = p.products_model
SET p.ytd_val = t.YTD_VAL
UPDATE And by the way you don't need that ORDER BY YTD_VAL DESC it has no sense in this particular case I guess.
UPDATE 2
UPDATE products p
INNER JOIN (
SELECT SUM(IF(YEAR(`ITDATE`) = YEAR(CURDATE() ), IF(ITTYPE = 'O',`ITVAL`, -`ITVAL` ), 0) ) as 'YTD_VAL',
IT_product_id
FROM `FITEMS`
WHERE (ITTYPE = 'O' OR `ITTYPE` = 'R')
AND ITBACKORDER = 'N' AND ITAMNT > 0 AND YEAR(`ITDATE`) >= YEAR(CURDATE() ) -1
GROUP BY `IT_product_id`
) t
ON t.IT_product_id = p.products_id
SET p.ytd_val = t.YTD_VAL
I am not one to say do it, but consider the case for Covering Indexes. One in particular on table fitems. Those columns are relatively slim for that query. I will spook up one to try on particular columns. We have seen cases where terribly long queries can be completed in snappy time. But no promises. Ah, I see you have some. Was looking at the first edit with the alter tables below it. I will keep looking.
Covering Index
A covering index is one in which the query can be resolved via a quick stroll through the index b-tree, without requiring a lookup into the actual table data page. These are the ultimate nirvana for speed. Percona quick article on it.
Explain
And run the query (the update one) thru Explain and examine the output. See also the article Using Explain to Write Better Mysql Queries.
Note, some of these comments are for those that follows, not necessarily this op. He seems to have his house in order pretty well.
In your subquery, neither the order by nor the group by are necessary, so the update can be written as:
UPDATE products p
SET p.ytd_val = (SELECT SUM(IF(YEAR(`ITDATE`) = YEAR(CURDATE() ), IF(ITTYPE = 'O',`ITVAL`, -`ITVAL` ), 0) )
FROM `FITEMS`
WHERE FITEMS.ITINCODE = p.products_model AND
ITTYPE IN ('O', 'R') AND
ITBACKORDER = 'N' AND
ITAMNT > 0 AND
YEAR(`ITDATE`) >= YEAR(CURDATE() ) - 1
);
For this, you want an index on FITEMS(ITINCODE, ITBACKORDER, ITTYPE, ITAMNT, ITVAL). This might significantly speed your query.

MySQL - Insert into a table by querying product id from another table

I have two tables.
Here is the structure
CREATE TABLE IF NOT EXISTS `CATALOG_CATEGORY_PRODUCT`
(
`CATEGORY_ID` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Category ID',
`PRODUCT_ID` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Product ID',
`POSITION` INT(11) NOT NULL DEFAULT '0' COMMENT 'Position',
PRIMARY KEY (`CATEGORY_ID`, `PRODUCT_ID`),
KEY `IDX_CATALOG_CATEGORY_PRODUCT_PRODUCT_ID` (`PRODUCT_ID`)
)
ENGINE=INNODB
DEFAULT CHARSET=UTF8
COMMENT='Catalog Product To Category Linkage Table';
CREATE TABLE IF NOT EXISTS `CATALOG_PRODUCT_ENTITY_TIER_PRICE`
(
`VALUE_ID` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Value ID',
`ENTITY_ID` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT
'Entity ID',
`ALL_GROUPS` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '1' COMMENT
'Is Applicable To All Customer Groups',
`CUSTOMER_GROUP_ID` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' COMMENT
'Customer Group ID',
`QTY` DECIMAL(12, 4) NOT NULL DEFAULT '1.0000' COMMENT 'QTY',
`VALUE` DECIMAL(12, 4) NOT NULL DEFAULT '0.0000' COMMENT
'Value',
`WEBSITE_ID` SMALLINT(5) UNSIGNED NOT NULL COMMENT 'Website ID',
PRIMARY KEY (`VALUE_ID`)
)
ENGINE=INNODB
DEFAULT CHARSET=UTF8
COMMENT='Catalog Product Tier Price Attribute Backend Table';
So I have around 500 products.
I queried the product ids from the catalog_category_product where category_id = 37
This is the query.
SELECT PRODUCT_ID
FROM `CATALOG_CATEGORY_PRODUCT`
WHERE CATEGORY_ID = 37
Using that result I would like to insert the price into tier price table.
INSERT INTO `CATALOG_PRODUCT_ENTITY_TIER_PRICE`
(`ENTITY_ID`,
`ALL_GROUPS`,
`CUSTOMER_GROUP_ID`,
`QTY`,
`VALUE`,
`WEBSITE_ID`)
VALUES (209,
1,
0,
60.0000,
10.0000,
0);
Here catalog_product_entity_tier_price.entity_id = catalog_category_product.product_id
So 209 is the first result of catalog_category_product query. I would like to do the same thing for all results.
Can someone help me with mysql query to accomplish that?
Try INSERT INTO ... SELECT ... like this:
INSERT INTO `catalog_product_entity_tier_price` (`entity_id`,
`all_groups`,
`customer_group_id`,
`qty`,
`value`,
`website_id`)
SELECT product_id, 1, 0, 60.0000, 10.0000, 0
FROM `catalog_category_product`
WHERE category_id =37
You could do an INSERT INTO ... SELECT statement like this:
INSERT INTO `catalog_product_entity_tier_price` (`entity_id`, `all_groups`, `customer_group_id`, `qty`, `value`, `website_id`)
SELECT product_id, 1, 0, 60.0000, 10.0000, 0
FROM `catalog_category_product`
WHERE category_id =37
This would insert one row per result of your SELECT query. All other columns would be the same in all inserted rows.
If you want other values in the other columns, you would have to specify them someway.

MySQL - Correct approach event counting

I want to list users which have a particular event count but I'm confused on which approach to take.
This is the database table:
CREATE TABLE `event` (
`event_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`visitor_id` int(11) DEFAULT NULL,
`key` varchar(200) DEFAULT NULL,
`value` text,
`label` varchar(200) DEFAULT '',
`datetime` datetime DEFAULT NULL,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `event` (`event_id`, `visitor_id`, `key`, `value`, `label`, `datetime`)
VALUES
(1, 1, 'LOGIN', NULL, '', NULL),
(2, 2, 'LOGIN', NULL, '', NULL),
(3, 1, 'VIEW_PAGE', 'HOTEL', '', NULL),
(4, 2, 'VIEW_PAGE', 'HOTEL', '', NULL),
(5, 1, 'PURCHASE_HOTEL', NULL, '', NULL);
CREATE TABLE `visitor` (
`visitor_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`datetime` datetime DEFAULT NULL,
PRIMARY KEY (`visitor_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `visitor` (`visitor_id`, `datetime`)
VALUES
(1, NULL),
(2, NULL);
and this is my approach:
SELECT DISTINCT
t1.`visitor_id`
FROM
`visitor` t1
JOIN `event` t2 on t1.visitor_id = t2.visitor_id AND t2.`key` = 'LOGIN'
JOIN `event` t3 on t1.visitor_id = t3.visitor_id AND t3.`key` = 'VIEW_PAGE' AND t3.`value` = 'HOTEL'
WHERE ( SELECT COUNT(*) FROM `event` WHERE `event`.`key` = 'PURCHASE_HOTEL' ) > 0
this should only list visitor 1 but it does actually list visitor 2 too which does not have the PURCHASE_HOTEL event.
As you can imagine, there will be more "rules" like all the JOIN events for each particular case. Can we correct and improve this somehow?
BONUS:
What is the name of this approach?
I think this is a "set-within-sets" query. I like using aggregation with a having clause for this type of query. The following checks the three conditions you are looking for:
select visitor_id
from event e
group by visitor_id
having sum(e.key = 'LOGIN') > 0 and
sum(e.key = 'VIEW_PAGE' and e.value = 'HOTEL') > 0 and
sum(e.key = 'PURCHASE_HOTEL') > 0;
The first condition in the having clause counts the number of LOGIN records and is true when at least one is found. (If you want exactly one, change > 0 to = 0.)
The second condition checks the viewing of the hotel page.
The third counts the number of hotel purchases.