MySQL gather data JOIN - mysql

I currently have these two tables
CREATE TABLE IF NOT EXISTS `players` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`group_id` int(11) NOT NULL DEFAULT '1',
`account_id` int(11) NOT NULL DEFAULT '0',
`level` int(11) NOT NULL DEFAULT '1',
`vocation` int(11) NOT NULL DEFAULT '0',
...
) ENGINE=InnoDB;
And
CREATE TABLE IF NOT EXISTS `player_storage` (
`player_id` int(11) NOT NULL DEFAULT '0',
`key` int(10) unsigned NOT NULL DEFAULT '0',
`value` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`player_id`,`key`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB;
I want to execute the following query
SELECT
a.value,
b.name,
b.level,
b.vocation
FROM
player_storage a,
players b
LEFT JOIN players_online c AS t
ON c.player_id = b.id
WHERE
a.player_id = b.id
AND a.key = 6723
ORDER BY a.value DESC LIMIT 20
Thing is I also want to see if the record exists on the table players_online
CREATE TABLE IF NOT EXISTS `players_online` (
`player_id` int(11) NOT NULL,
PRIMARY KEY (`player_id`)
) ENGINE=MEMORY;
However my query seems to work but its not getting if the player_id exists on players_online
I only get the fields value, name, level, vocation but not a single field related to players_online

You should add a field related to your "online" table.
For example:
SELECT ...,
IF(c.player_id IS NULL, 'offline', 'online') online
FROM ...
And sure, you must to fix issue with double alias in players_online c As t
SQLFiddle

Related

Unknown column in 'on clause' after MySQL upgrade

I've been updating some old code which used PHP4 and MySQL 4.1 up to MySQL 5.6 / MariaDB 10. I've had a few issues with SQL JOINs
and precedence but this one has really stumped me and is giving me the error -
#1054 - Unknown column 'grouping_id' in 'on clause'
I've tried messing about with the order of the JOIN statements in the query below but I haven't had any success yet, as mentioned this query worked fine on MySQL 4.
SELECT
team.team_id,
team.team_name,
competition.rel_sport_id,
country.country_name
FROM
team
LEFT JOIN team_grouping ON(
rel_team_id = team_id AND team_grouping.rel_grouping_id = grouping_id
)
LEFT JOIN grouping ON grouping_id = team_grouping.rel_grouping_id
LEFT JOIN country ON team.rel_country_id = country_id
LEFT JOIN sport ON team.rel_sport_id = sport_id
LEFT JOIN competition_country ON(
rel_competition_id = competition_id AND competition_country.rel_country_id = country_id
)
LEFT JOIN competition ON competition_id = '985'
WHERE
team.rel_country_id = competition_country.rel_country_id AND team.rel_sport_id = competition.rel_sport_id AND grouping_id = '3'
ORDER BY
team_name
Can anyone help with what could be wrong with the above query?
EDIT - Added table schemas:
CREATE TABLE `grouping` (
`grouping_id` int(11) NOT NULL AUTO_INCREMENT,
`grouping_name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`grouping_id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin
CREATE TABLE `team` (
`team_id` int(11) NOT NULL AUTO_INCREMENT,
`team_name` varchar(200) DEFAULT NULL,
`image` varchar(100) DEFAULT NULL,
`rel_country_id` int(11) DEFAULT NULL,
`rel_sport_id` int(11) DEFAULT NULL,
`modified_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`team_id`),
KEY `IDX_team_1` (`rel_country_id`),
KEY `IDX_team_2` (`rel_sport_id`)
) ENGINE=MyISAM AUTO_INCREMENT=11918 DEFAULT CHARSET=latin1
CREATE TABLE `country` (
`country_id` int(11) NOT NULL AUTO_INCREMENT,
`country_name` varchar(40) DEFAULT NULL,
`image` varchar(40) DEFAULT NULL,
`rel_geographic_id` int(11) DEFAULT NULL,
PRIMARY KEY (`country_id`),
KEY `IDX_country_2` (`rel_geographic_id`)
) ENGINE=MyISAM AUTO_INCREMENT=237 DEFAULT CHARSET=latin1
CREATE TABLE `competition` (
`competition_id` int(11) NOT NULL AUTO_INCREMENT,
`competition_name` varchar(200) DEFAULT NULL,
`rel_sport_id` int(11) DEFAULT NULL,
`rel_grouping_id` int(11) DEFAULT NULL,
`rel_competition_tz_id` int(11) NOT NULL DEFAULT '2',
`modified_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`competition_id`),
KEY `IDX_competition_1` (`rel_sport_id`),
KEY `IDX_competition_2` (`rel_grouping_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1133 DEFAULT CHARSET=latin1
CREATE TABLE `sport` (
`sport_id` int(11) NOT NULL AUTO_INCREMENT,
`sport_name` varchar(40) DEFAULT NULL,
`image` varchar(40) DEFAULT NULL,
`modified_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`sport_id`)
) ENGINE=MyISAM AUTO_INCREMENT=29 DEFAULT CHARSET=latin1
CREATE TABLE `competition_country` (
`rel_competition_id` int(11) NOT NULL DEFAULT '0',
`rel_country_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`rel_competition_id`,`rel_country_id`),
KEY `IDX_competition_country_1` (`rel_competition_id`),
KEY `IDX_competition_country_2` (`rel_country_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Table names in an ON clause can only refer to tables preceding it in the query. When you're joining through a relationship table, the first ON clause just relates with the table before it, you relate to the second table in the next ON clause.
So the ON clause for team_grouping should only have rel_team_id = team_id, and the ON clause for competition_country should only have rel_country_id = country_id.
I don't think you need the WHERE clause at the end. Those relationships should be implied already by the earlier joins. And since you're doing a LEFT JOIN with grouping, you should put restrictions on that table in the ON clause; otherwise, the null values from non-matching rows will be filtered out by the WHERE clause.
SELECT
team.team_id,
team.team_name,
competition.rel_sport_id,
country.country_name
FROM team
LEFT JOIN team_grouping ON rel_team_id = team_id
LEFT JOIN grouping ON grouping_id = team_grouping.rel_grouping_id AND grouping_id = 3
LEFT JOIN country ON team.rel_country_id = country_id
LEFT JOIN sport ON team.rel_sport_id = sport_id
LEFT JOIN competition_country ON competition_country.rel_country_id = country_id
LEFT JOIN competition ON competition_id = '985' AND competition_id = competition_country.rel_competition_id
ORDER BY team_name

how can i extract total forum_question and fourm_answer count as subject wise in mysql i have below mysql structure

forum_question :
CREATE TABLE IF NOT EXISTS `forum_question` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`question` text NOT NULL,
`subject_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `subject_id` (`subject_id`,`student_id`),
KEY `student_id` (`student_id`)
)
forum_answer table
CREATE TABLE IF NOT EXISTS `forum_answer` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`answer` text NOT NULL,
`question_id` int(11) NOT NULL,
`faculty_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `question_id` (`question_id`,`faculty_id`),
KEY `faculty_id` (`faculty_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
and subject table
CREATE TABLE IF NOT EXISTS `subject` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(150) NOT NULL
)
Try this edited query, I am sure this will work
SELECT
COUNT(que.id) AS totalQuestions,
(SELECT COUNT(DISTINCT(forum_answer.id))
FROM
forum_answer
WHERE
forum_answer.question_id = que.id
GROUP BY que.id)
AS totalAns
FROM
forum_question que
INNER JOIN
subject sub
ON (que.subject_id = sub.id)
WHERE
que.id > 0
GROUP BY sub.id
If by total you mean the total amount of rows, you can do the following:
`SELECT COUNT(*) FROM forum_question WHERE subject_id=YOURSUBJECT`
if you want just all rows, remove the WHERE clause.
Please you can try this Query
SELECT
subject.name AS subject_name,
count(forum_question.id) AS total_question,
(SELECT count(forum_answer.id)
FROM
forum_answer
WHERE
forum_answer.question_id = forum_question.id) AS total_answer
FROM
subject
Inner Join forum_question ON subject.id = forum_question.subject_id
GROUP BY subject.id
Sorry it was my mistake. now I edited the query and hope it will work for you

mysql gives NULL for record in a table if JOIN and COUNT used but SELECT works fine why?

Table 1
CREATE TABLE IF NOT EXISTS `com_msg` (
`msg_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`msg_to` int(10) NOT NULL,
`msg_from` int(10) NOT NULL,
`msg_new` tinyint(1) unsigned NOT NULL DEFAULT '1',
`msg_content` varchar(300) NOT NULL,
`msg_date` date NOT NULL,
`bl_sender` tinyint(1) unsigned NOT NULL DEFAULT '0',
`bl_recip` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`msg_id`),
UNIQUE KEY `msg_id` (`msg_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Table 2
CREATE TABLE IF NOT EXISTS `ac_vars` (
`user_id` int(10) unsigned NOT NULL,
`ac_ballance` smallint(3) unsigned NOT NULL DEFAULT '0',
`prof_views` mediumint(8) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`),
UNIQUE KEY `id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
When I use query :
SELECT ac_ballance, prof_views, COUNT( msg_id ) AS messages
FROM ac_vars
INNER JOIN com_msg ON user_id = msg_to
WHERE user_id =".$userid." AND com_msg.msg_new =1;
I get :
ac_ballance=NULL(incorrect)
prof_views=NULL(incorrect)
messages=0(correct)
But with Select statement just on ac_vars I get correct values, what is the correct way of doing this?
You want rows from the table ac_vars even when there's no corresponding row in the table com_msg.
So you must use a LEFT JOIN:
SELECT ac_ballance, prof_views, COUNT( msg_id ) AS messages
FROM ac_vars
LEFT JOIN com_msg
ON user_id = msg_to AND com_msg.msg_new =1
WHERE user_id =".$userid.";
Please note that the condition
com_msg.msg_new =1
got to be a part of the JOIN condition and not the WHERE clause, because there's no value in com_msg that fulfills this condition.
Note
Adding
GROUP BY ac_ballance, prof_views
is not needed by MySQLs optimization because the values in those columns are directly dependent of the user_id and the WHERE clause permits only one single row.

Very slow mysql query for reading orders (joins and group by)

A query for reading orders is very slow. I've tried a lot of things, but couldn't get a faster query. Below the query and the database tables. Of course, all the important fields have an index. I noticed that removing the group by function will speed it up, but grouping the query is important.
is there a better way for getting the orders? Thanks in advance.
SELECT
orders.id AS orderId, orders.delivery_from, orders.delivery_to,
orders_products.product_id, orders_products.color_id, ,orders_products.size_id,
sum(orders_products.quantity) as quantity,
customers.id AS customerId, customers.name AS customerName,
products.name
FROM orders
INNER JOIN orders_products ON orders_products.order_id=orders.id
INNER JOIN customers ON customers.id=orders.customer_id
INNER JOIN products ON orders_products.product_id=products.id
LEFT JOIN orders_product_data ON orders_product_data.order_id=orders.id AND orders_product_data.product_id=orders_product.product_id AND orders_product_data.color_id=orders_product.color_id
WHERE orders.status='0' AND
(orders.delivery_from<='2014-05-05' AND orders.delivery_to>='2014-05-05') AND
((orders_products_data.delivery_from<='2014-05-05' || orders_products_data.delivery_to=0) AND (orders_products_data.delivery_from>='2014-05-05' || orders_products_data.delivery_to=0))
GROUP BY customer_id, product_id, color_id, size_id
Customers
CREATE TABLE IF NOT EXISTS `customers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(90) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
);
Products
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
);
Orders
CREATE TABLE IF NOT EXISTS `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`customer_id` int(11) NOT NULL,
`delivery_from` date NOT NULL,
`delivery_to` date NOT NULL,
`status` int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
);
Products of the order
CREATE TABLE IF NOT EXISTS `orders_products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL DEFAULT '0',
`product_id` int(11) NOT NULL DEFAULT '0',
`color_id` int(11) NOT NULL DEFAULT '0',
`size_id` int(11) NOT NULL DEFAULT '0',
`quantity` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
);
Color data. The tabel below stores for the combination order_id, product_id and color_id the delivery information since the delivery of products in different colors could change.
CREATE TABLE IF NOT EXISTS `orders_products_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL DEFAULT '0',
`product_id` int(11) NOT NULL DEFAULT '0',
`color_id` int(11) NOT NULL DEFAULT '0',
`delivery_from` date NOT NULL,
`delivery_to` date NOT NULL,
PRIMARY KEY (`id`)
);
The explain query
You have mentioned that you have indexes for all the important fields.
Just for your Info - Index should be prepared based on the access path rather than for important fields.
Check after replacing delivery_from between '...' and '...' for orders, orders_product_data and adding following index:
create index idx_orders_status_delivery_from_to on orders(status,delivery_from,delivery_to);

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'
...