MySQL join empty rows - mysql

I'm trying to construct a simple query in for getting users with particular meta fields (this is in Wordpress, but doesn't matter cause it's raw sql)
A simple query i did looks like this
SELECT * FROM wp_sb_users u
LEFT OUTER JOIN wp_sb_usermeta m ON (u.ID=m.user_id)
LEFT OUTER JOIN wp_sb_usermeta mm ON (u.ID=mm.user_id)
LEFT OUTER JOIN wp_sb_usermeta mmm ON (u.ID=mmm.user_id)
WHERE
m.meta_key = "autostatus" AND
mm.meta_key = "first_name" AND
mmm.meta_key = "last_name"
though i have only one small trouble -- if mmm.meta_key = "last_name" doesn't exist at all, the row isn't returned.. i tried mmm.meta_key <=> "last_name" but then it takes any other meta_key (like "user_email") and puts there in row, which then results in having a user with first name Alex and last name my#email.com
I also tried (mmm.meta_key = "last_name" OR mmm.meta_key IS NULL), but it doesn't work too
Help me figure it out please
PS
the tables structure:
CREATE TABLE IF NOT EXISTS `wp_sb_users` (
`ID` bigint(20) unsigned NOT NULL auto_increment,
`user_login` varchar(60) NOT NULL default '',
`user_pass` varchar(64) NOT NULL default '',
`user_nicename` varchar(50) NOT NULL default '',
`user_email` varchar(100) NOT NULL default '',
`user_url` varchar(100) NOT NULL default '',
`user_registered` datetime NOT NULL default '0000-00-00 00:00:00',
`user_activation_key` varchar(60) NOT NULL default '',
`user_status` int(11) NOT NULL default '0',
`display_name` varchar(250) NOT NULL default '',
PRIMARY KEY (`ID`),
KEY `user_login_key` (`user_login`),
KEY `user_nicename` (`user_nicename`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=30 ;
CREATE TABLE IF NOT EXISTS `wp_sb_usermeta` (
`umeta_id` bigint(20) unsigned NOT NULL auto_increment,
`user_id` bigint(20) unsigned NOT NULL default '0',
`meta_key` varchar(255) default NULL,
`meta_value` longtext,
PRIMARY KEY (`umeta_id`),
KEY `user_id` (`user_id`),
KEY `meta_key` (`meta_key`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=792 ;

SELECT * FROM wp_sb_users u
LEFT OUTER JOIN wp_sb_usermeta m ON (u.ID=m.user_id and m.meta_key = "autostatus")
LEFT OUTER JOIN wp_sb_usermeta mm ON (u.ID=mm.user_id and mm.meta_key = "first_name")
LEFT OUTER JOIN wp_sb_usermeta mmm ON (u.ID=mmm.user_id and mmm.meta_key = "last_name")

Related

optimize the mysql query

I have following mysql query which is taking long time(40s) to load the results.
SELECT SQL_CALC_FOUND_ROWS blog_posts.ID FROM blog_posts
LEFT JOIN blog_term_relationships AS tt0 ON (blog_posts.ID = tt0.object_id)
LEFT JOIN blog_term_relationships AS tt1 ON (blog_posts.ID = tt1.object_id)
LEFT JOIN blog_term_relationships AS tt2 ON (blog_posts.ID = tt2.object_id)
LEFT JOIN blog_term_relationships AS tt3 ON (blog_posts.ID = tt3.object_id)
WHERE 1=1
AND ( ( tt0.term_taxonomy_id IN (141,177) AND tt1.term_taxonomy_id IN (2389,2390) )
OR ( tt2.term_taxonomy_id IN (167,1169,1715) AND tt3.term_taxonomy_id IN (2519,2520) ) )
AND blog_posts.post_type = 'post' AND (blog_posts.post_status = 'publish')
GROUP BY blog_posts.ID ORDER BY blog_posts.post_date ASC LIMIT 0, 20
Is there any way to optimize this query.
Edit:
This is related to wordpress and this query was automatically create from the wp_query.
Table structures as bellow,
blog_posts table:
CREATE TABLE `blog_posts` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
`post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content` longtext NOT NULL,
`post_title` text NOT NULL,
`post_excerpt` text NOT NULL,
`post_status` varchar(20) NOT NULL DEFAULT 'publish',
`comment_status` varchar(20) NOT NULL DEFAULT 'open',
`ping_status` varchar(20) NOT NULL DEFAULT 'open',
`post_password` varchar(255) NOT NULL DEFAULT '',
`post_name` varchar(200) NOT NULL DEFAULT '',
`to_ping` text NOT NULL,
`pinged` text NOT NULL,
`post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content_filtered` longtext NOT NULL,
`post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`guid` varchar(255) NOT NULL DEFAULT '',
`menu_order` int(11) NOT NULL DEFAULT '0',
`post_type` varchar(20) NOT NULL DEFAULT 'post',
`post_mime_type` varchar(100) NOT NULL DEFAULT '',
`comment_count` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
KEY `post_parent` (`post_parent`),
KEY `post_author` (`post_author`),
KEY `post_name` (`post_name`(191))
) ENGINE=MyISAM AUTO_INCREMENT=125636 DEFAULT CHARSET=utf8
blog_term_relationships table:
CREATE TABLE `blog_term_relationships` (
`object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_order` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`object_id`,`term_taxonomy_id`),
KEY `term_taxonomy_id` (`term_taxonomy_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
EXPLAIN QUERY:
enter image description here
Reformulate
SELECT SQL_CALC_FOUND_ROWS blog_posts.ID
FROM (
(
SELECT object_id
FROM blog_term_relationships AS tt0
JOIN blog_term_relationships AS tt1 USING(object_id)
WHERE tt0.term_taxonomy_id IN (141,177)
AND tt1.term_taxonomy_id IN (2389,2390)
)
UNION DISTINCT
(
SELECT object_id
FROM blog_term_relationships AS tt2
JOIN blog_term_relationships AS tt3 USING(object_id)
WHERE tt2.term_taxonomy_id IN (167,1169,1715)
AND tt3.term_taxonomy_id IN (2519,2520) )
) AS tt
JOIN blog_posts ON blog_posts.ID = tt.object_id
WHERE blog_posts.post_type = 'post'
AND blog_posts.post_status = 'publish'
ORDER BY blog_posts.post_date ASC
LIMIT 0, 20
This gets rid of the GROUP BY and does several other things to speed up the query.
Prefix index
`post_name` varchar(200) NOT NULL DEFAULT '',
KEY `post_name` (`post_name`(191))
) ENGINE=MyISAM AUTO_INCREMENT=125636 DEFAULT CHARSET=utf8
Make up your mind -- 191 is for version 5.6 with utf8mb4 (which you have not specified); 191 is so close to 200, you may as well make it VARCHAR(191). Getting rid of the prefix index is likely to speed up some of your queries.
InnoDB
Don't use MyISAM, move to InnoDB. That is for performance, robustness, etc. That will coincidentally fix an inefficiency in KEY term_taxonomy_id).
SQL_CALC_FOUND_ROWS
SQL_CALC_FOUND_ROWS is costly. It's purpose is passe.

sql can't figure out the query

I have three tables:
CREATE TABLE IF NOT EXISTS `contacts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`providerId` int(10) unsigned NOT NULL DEFAULT '0',
`requestId` int(10) unsigned NOT NULL DEFAULT '0',
`status` binary(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
CREATE TABLE IF NOT EXISTS `messages` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`fromuid` int(255) NOT NULL,
`touid` int(255) NOT NULL,
`sentdt` datetime NOT NULL,
`read` tinyint(1) NOT NULL DEFAULT '0',
`readdt` datetime DEFAULT NULL,
`messagetext` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`),
KEY `id` (`id`)
)
CREATE TABLE IF NOT EXISTS `users` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`mobile` varchar(15) NOT NULL,
`password` varchar(255) NOT NULL,
`city` varchar(255) NOT NULL,
`zip` varchar(15) DEFAULT NULL,
`device` varchar(50) DEFAULT NULL,
`version` varchar(10) DEFAULT NULL,
`photo` varchar(255) DEFAULT NULL,
`created` datetime NOT NULL,
`live` enum('0','1') NOT NULL DEFAULT '1',
`authenticationTime` datetime NOT NULL,
`userKey` varchar(255) DEFAULT NULL,
`IP` varchar(50) DEFAULT NULL,
`port` int(10) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `firstname` (`mobile`,`city`,`zip`)
)
And this SQL query that finds out friends/contacts for specified user (user id 1 in this case):
SELECT u.id
,u.mobile
,u.name
,(NOW() - u.authenticationTime) AS authenticateTimeDifference
,u.IP
,f.providerid
,f.requestid
,f.status
,u.port
FROM contacts f
LEFT JOIN users u ON u.id =
IF (
f.providerid = 1
,f.requestid
,f.providerid
) WHERE (
f.providerid = 1
AND f.status = 1
)
OR f.requestid = 1
That works fine but I want to be able to also join messages table and show user's friends/contacts who have talked latest (meaning latest conversations first) with order by messages.sentdt desc option but I am unable to figure out how to do that, I tried all joins but none worked :(
Your help will be greatly appreciated. Thanks
Update
Here is sample data above query returns:
In that same resultset, I want to be able to sort based on order by messages.sentdt desc but I am not sure how to pull that in and sort resultset by latest message first
Try this:
select u.id
, u.mobile
, u.name
, (NOW() - u.authenticationTime) as authenticateTimeDifference
, u.IP
, f.providerid
, f.requestid
, f.status
, u.port
from contacts f
left join users u
on u.id = if (f.providerid = 1, f.requestid, f.providerid)
left join (select fromuid, max(sentdt) as sentdt from messages group by fromuid) m
on m.fromuid = if (f.providerid = 1, f.providerid, f.requestid)
where (f.providerid = 1 and f.status = 1)
or f.requestid = 1
order by m.sentdt

How to optimize my query? Exporting Wordpress posts with category and tag list

I wrote query for export posts.
SELECT
post_name,
post_content,
Categories,
Tags
FROM
-- posts
wp_posts as p
-- categories
LEFT JOIN
(SELECT
object_id as cat_obj_id,
GROUP_CONCAT(cat_term.name) as Categories
FROM
wp_term_relationships AS cat_r
JOIN wp_term_taxonomy AS cat_tax
ON cat_r.term_taxonomy_id = cat_tax.term_taxonomy_id
JOIN wp_terms AS cat_term
ON cat_tax.term_id = cat_term.term_id
WHERE cat_tax.taxonomy="category"
GROUP by object_id)
as c
ON p.id = c.cat_obj_id
-- tags
LEFT JOIN
(SELECT
object_id as tag_obj_id,
GROUP_CONCAT(tag_term.name) as Tags
FROM
wp_term_relationships AS tag_r
JOIN wp_term_taxonomy AS tag_tax
ON tag_r.term_taxonomy_id = tag_tax.term_taxonomy_id
JOIN wp_terms AS tag_term
ON tag_tax.term_id = tag_term.term_id
WHERE tag_tax.taxonomy="post_tag"
GROUP by object_id)
as t
ON p.id = t.tag_obj_id
Table schemas:
CREATE TABLE `wp_term_taxonomy` (
`term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`term_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`taxonomy` varchar(32) NOT NULL DEFAULT '',
`description` longtext NOT NULL,
`parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`count` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`term_taxonomy_id`),
UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`),
KEY `taxonomy` (`taxonomy`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8$$
CREATE TABLE `wp_term_relationships` (
`object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_order` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`object_id`,`term_taxonomy_id`),
KEY `term_taxonomy_id` (`term_taxonomy_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8$$
CREATE TABLE `wp_terms` (
`term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL DEFAULT '',
`slug` varchar(200) NOT NULL DEFAULT '',
`term_group` bigint(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`term_id`),
UNIQUE KEY `slug` (`slug`),
KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8$$
CREATE TABLE `wp_posts` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
`post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content` longtext NOT NULL,
`post_title` text NOT NULL,
`post_excerpt` text NOT NULL,
`post_status` varchar(20) NOT NULL DEFAULT 'publish',
`comment_status` varchar(20) NOT NULL DEFAULT 'open',
`ping_status` varchar(20) NOT NULL DEFAULT 'open',
`post_password` varchar(20) NOT NULL DEFAULT '',
`post_name` varchar(200) NOT NULL DEFAULT '',
`to_ping` text NOT NULL,
`pinged` text NOT NULL,
`post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content_filtered` longtext NOT NULL,
`post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`guid` varchar(255) NOT NULL DEFAULT '',
`menu_order` int(11) NOT NULL DEFAULT '0',
`post_type` varchar(20) NOT NULL DEFAULT 'post',
`post_mime_type` varchar(100) NOT NULL DEFAULT '',
`comment_count` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `post_name` (`post_name`),
KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
KEY `post_parent` (`post_parent`),
KEY `post_author` (`post_author`)
) ENGINE=MyISAM AUTO_INCREMENT=9082 DEFAULT CHARSET=utf8$$
EXPLAIN:
Running this query on 1000 posts database takes 72 seconds (execute under 1 sec, fetching takes forever). Is there any way to make it faster, without temporary tables to store categories and tags?
I discovered, that my big query runs horribly slow when there are no records on one of subqueries, that are LEFT JOIN'ed.
To workaround this - I created temporary tables from subqueries and I replaced subqueries with these temporary tables.
Here is my SQL.
-- 1.1. Creating table for post categories
create table if not exists temp_categories
(
ID bigint not null AUTO_INCREMENT,
Categories text not null,
PRIMARY KEY (ID)
) DEFAULT CHARSET=utf8;
-- 1.2. Filling table temp_categories
INSERT INTO temp_categories(ID, Categories)
SELECT
'object_id' AS ID, -- post ID
GROUP_CONCAT(cat_term.name ORDER BY cat_term.name) AS Categories -- comma separated category list
FROM
wp_term_relationships AS cat_r
JOIN wp_term_taxonomy AS cat_tax
ON cat_r.term_taxonomy_id = cat_tax.term_taxonomy_id
JOIN wp_terms AS cat_term
ON cat_tax.term_id = cat_term.term_id
WHERE cat_tax.taxonomy="category"
GROUP by object_id;
-- 2.1. Creating table for post tags
create table temp_tags
(
ID bigint not null AUTO_INCREMENT,
Tags text not null,
PRIMARY KEY (ID)
) DEFAULT CHARSET=utf8 ;
-- 2.2. Filling table temp_tags
INSERT INTO exp_tagi(ID, Tagi)
SELECT
object_id AS ID, --post ID
GROUP_CONCAT(tag_term.name ORDER BY tag_term.name) AS Tags -- comma separated tag list
FROM
wp_term_relationships AS tag_r
JOIN wp_term_taxonomy AS tag_tax
ON tag_r.term_taxonomy_id = tag_tax.term_taxonomy_id
JOIN wp_terms AS tag_term
ON tag_tax.term_id = tag_term.term_id
WHERE tag_tax.taxonomy="post_tag"
GROUP by object_id;
-- 3. Exporting posts
SELECT
p.id AS id,
p.post_title AS Title,
p.post_content AS Content,
k.Categories AS Categories,
t.Tags AS Tags,
IF(p.post_status = 'publish', 1, 0) AS Published
FROM
wp_posts p
left join temp_categories k
on p.id = k.id
left join temp_tags t
on p.id = t.id
WHERE post_status in('publish', 'draft')
ORDER BY id;
-- 4. Deleting temporary tables
DROP TABLE temp_categories;
DROP TABLE temp_tags;
I could use TEMPORARY tables (no need for delete, they disappear when MySQL session ends), but I didnt because my PHP app ends MySQL session after each query.

Join two tables only if a value is null or a specific number

I have three tables in a database:
Product table - +100000 entries
Attribute table (list of possible attributes of a product)
Product attribtue table (which contains the value of the attribute of a product)
I am looking for 8 random products and one of their attributes (attribute_id = 2), but if a product hasn't this attribute it should appear at the return of the query. I have been trying some sql queries without any succesful result because my return only shows the products that have the attribute and hide the others.
My three tables are like this:
CREATE TABLE `product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sku` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`name` varchar(90) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`provider_id` int(11) unsigned DEFAULT NULL,
`url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`active` int(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `sku_UNIQUE` (`sku`)
) ENGINE=InnoDB AUTO_INCREMENT=123965 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `attribute` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT '',
`data_type` varchar(50) DEFAULT '',
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1;
CREATE TABLE `product_attribute` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`product_id` int(11) unsigned NOT NULL,
`attribute_id` int(11) unsigned NOT NULL DEFAULT '6',
`value` longtext NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `product_id` (`product_id`,`attribute_id`)
) ENGINE=InnoDB AUTO_INCREMENT=869437 DEFAULT CHARSET=latin1;
And this is one of the queries I tried, I thought it was correct but it have the same problem as the others...
SELECT product.id, product.sku, product.name,provider.name as provider_name,
product_attribute.value as author
FROM (`product`)
LEFT JOIN `provider` ON `product`.`provider_id` = `provider`.`id`
LEFT JOIN `product_attribute` ON `product`.`id` = `product_attribute`.`product_id`
WHERE `product`.`active` = '1' AND `product`.`url` IS NOT NULL
AND (`product_attribute`.`attribute_id` = 8 OR `product_attribute`.`attribute_id` IS NULL)
AND `product`.`provider_id` = '7' ORDER BY RAND() LIMIT 8
I was trying with left, inner and right join and nothing works.
You should put the condition for the left-joined table in the join, not the where clause
...
from product
left join provider ON product.provider_id = provider.id
left join product_attribute on product.id = product_attribute.product_id
and product_attribute.attribute_id = 8
where `product`.`active` = '1'
and `product`.`url` IS NOT NULL
and `product`.`provider_id` = '7'
...

MySQL join problem

I want to join a pages table and menu table.
CREATE TABLE IF NOT EXISTS `pages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`keywords` varchar(255) NOT NULL DEFAULT '',
`description` varchar(255) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`content` text NOT NULL,
`status` enum('active','inactive') NOT NULL DEFAULT 'active',
`category_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
CREATE TABLE IF NOT EXISTS `menus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`shortdesc` varchar(255) NOT NULL,
`page_id` varchar(60) NOT NULL,
`status` enum('active','inactive') NOT NULL,
`parentid` int(11) NOT NULL,
`order` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=79 ;
I have errors with the following SQL.
function generateTree(&$tree, $parentid = 0) {
$res = $this->db->query('SELECT M.*, P.name AS PageName
WHERE M.parentid = $parentid
ORDER BY M.order asc, M.parentid asc
FROM menus AS M
LEFT JOIN pages AS P
ON P.id = M.page_id');
...
...
Can you tell what I am doing wrong?
Thanks in advance.
You've got your SQL syntax mixed up
$res = $this->db->query('
SELECT
M.*, P.name AS PageName
FROM
menus AS M
LEFT JOIN pages AS P ON P.id = M.page_id
WHERE
M.parentid = $parentid
ORDER BY
M.order asc, M.parentid asc
');
BTW, you should bot be using variables in the SQL string. Use parameterized queries instead (mysyqli*).