Internationalization of sql query - mysql

I have the following SQL tables:
-- Create syntax for TABLE 'companies'
CREATE TABLE `companies` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`country` varchar(255) NOT NULL DEFAULT '',
`city` varchar(255) NOT NULL DEFAULT '',
`address` text NOT NULL,
`logo` varchar(255) NOT NULL DEFAULT 'empty',
`size` int(11) NOT NULL DEFAULT '32',
PRIMARY KEY (`id`),
KEY `city` (`city`),
KEY `country` (`country`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
-- Create syntax for TABLE 'i18n'
CREATE TABLE `i18n` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`lang` varchar(2) DEFAULT NULL,
`word` text,
`english` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- Create syntax for TABLE 'tags'
CREATE TABLE `tags` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
-- Create syntax for TABLE 'tagsForCompany'
CREATE TABLE `tagsForCompany` (
`company` int(11) DEFAULT NULL,
`tid` int(11) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I have the following sql query (thanks to #Rockse):
SELECT c.*
FROM
(SELECT *
FROM companies
WHERE city = "<Some City>" AND country = "<Some Country>") AS c
INNER JOIN tagsForCompany AS tc ON c.id = tc.Company
INNER JOIN tags AS t ON t.id = tc.TID
WHERE t.Name REGEXP '<a keyword>'
I need to be able to search for Companies with a keyword written in another language by searching in the i18n table for a translation. So that searching for restaurant will give the same results as searching for レストラン (restaurant in Japanese) or ristorante (restaurant in italian).
Honestly I have no idea what to edit in the query, my SQL knowledge is a bit limited.

The solution was easier than I thought:
If someone would improve, I would be more than happy
SELECT c.*
FROM i18n, (SELECT *
FROM companies
WHERE city = "<some city>" AND country = "<some country>") AS c
INNER JOIN tagsForCompany AS tc ON c.id = tc.Company
INNER JOIN tags AS t ON t.id = tc.TID
WHERE t.Name = i18n.`english` AND i18n.word REGEXP "<some word>" OR t.Name REGEXP "<the same word as before>"
But for doing that I had to change all the tables to utf-8

Related

MySQL Select Query running very slow

I have a MySQL query that works but is very slow. I am guessing due to the amount of joins.
SELECT
order_header.order_head_id,
order_header.order_date,
order_header.status,
suppliers.supplier,
categories.category,
order_header.user,
order_header.sage_ref,
SUM(order_lines.total_price) AS price
FROM
order_header
LEFT JOIN
order_lines ON order_header.order_head_id = order_lines.order_head_id
LEFT JOIN
suppliers ON order_header.supplier_id = suppliers.supp_id
LEFT JOIN
categories ON order_header.category = categories.cat_id
WHERE
order_header.status LIKE '%'
AND order_header.order_head_id LIKE '%'
AND order_header.user LIKE '%'
GROUP BY order_header.order_head_id
ORDER BY order_head_id DESC
LIMIT 50;
Results of the EXPLAIN query
SHOW CREATE TABLE results
CREATE TABLE `categories` (
`cat_id` int(11) NOT NULL AUTO_INCREMENT,
`category` varchar(45) DEFAULT NULL,
`status` varchar(45) DEFAULT NULL,
PRIMARY KEY (`cat_id`)
) ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=latin1
CREATE TABLE `order_header` (
`order_head_id` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(45) DEFAULT NULL,
`category` varchar(45) NOT NULL,
`order_date` date DEFAULT NULL,
`supplier_id` varchar(45) NOT NULL,
`user` varchar(45) DEFAULT NULL,
`sage_ref` varchar(45) DEFAULT NULL,
`query_notes` varchar(500) DEFAULT NULL,
PRIMARY KEY (`order_head_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2249 DEFAULT CHARSET=latin1
CREATE TABLE `order_lines` (
`order_lines_id` int(11) NOT NULL AUTO_INCREMENT,
`order_head_id` int(11) DEFAULT NULL,
`qty` int(11) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`unit_price` decimal(65,2) DEFAULT NULL,
`total_price` decimal(65,2) DEFAULT NULL,
PRIMARY KEY (`order_lines_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3981 DEFAULT CHARSET=latin1
CREATE TABLE `suppliers` (
`supp_id` int(11) NOT NULL AUTO_INCREMENT,
`supplier` varchar(255) DEFAULT NULL,
`status` varchar(225) DEFAULT NULL,
PRIMARY KEY (`supp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=161 DEFAULT CHARSET=latin1
SQL Version 5.6.30
I am not great on MySQL and was wondering if anyone can see a way to improve the query so that it runs quicker.
Your help would be gratefully appreciated.
Many thanks,
John
It can make sense to wrap the first (left) join into a GROUP BY subquery. GROUP BY and LIMIT will limit the number of row which will be used in the following two joins:
SELECT
x.order_head_id,
x.order_date,
x.status,
suppliers.supplier,
categories.category,
x.user,
x.sage_ref,
x.price
FROM (
SELECT
order_header.supplier_id,
order_header.category,
order_header.order_head_id,
order_header.order_date,
order_header.status,
order_header.user,
order_header.sage_ref,
SUM(order_lines.total_price) AS price
FROM order_header
LEFT JOIN order_lines ON order_header.order_head_id = order_lines.order_head_id
WHERE order_header.status LIKE '%'
AND order_header.order_head_id LIKE '%'
AND order_header.user LIKE '%'
GROUP BY order_header.order_head_id
ORDER BY order_head_id DESC
LIMIT 50
) x
LEFT JOIN suppliers ON x.supplier_id = suppliers.supp_id
LEFT JOIN categories ON x.category = categories.cat_id
ORDER BY order_head_id DESC

Convert MySQL subquery to JOIN query

I'm trying to get the quotes.quote, authors.author and tags.tag from the following table structure,
CREATE TABLE IF NOT EXISTS `authors` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`author` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `quotes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`quote` text COLLATE utf8_unicode_ci NOT NULL,
`author_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `quotes_author_id_foreign` (`author_id`),
);
CREATE TABLE IF NOT EXISTS `quote_tags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tag_id` int(10) unsigned NOT NULL,
`quote_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `tags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tag` varchar(225) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
);
ALTER TABLE `quotes`
ADD CONSTRAINT `quotes_author_id_foreign` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`);
But here the problem is, there can be multiple entry in the tags table for each quotes and I want to retrieve it in the comma separated format.
Here is what I have tried so far,
SELECT `quotes`.`id` , `quotes`.`quote` , `authors`.`author` , (
SELECT GROUP_CONCAT( `tag` )
FROM tags
JOIN quote_tags
WHERE quote_tags.tag_id = tags.id
AND quote_tags.quote_id = quotes.id
) as tags
FROM `quotes`
INNER JOIN `authors` ON `authors`.`id` = `quotes`.`author_id`
INNER JOIN `topics`
But I don't want to use sub queries to get that done.
Please help me in building this query without using sub queries.
SELECT `_quotes`.`id` , `_quotes`.`quote` , `_authors`.`author`
,GROUP_CONCAT( `tag` )
FROM `_quotes`
INNER JOIN `_authors` ON `_authors`.`id` = `_quotes`.`author_id`
inner join _tags
JOIN _quote_tags
on _quote_tags.tag_id = _tags.id
AND _quote_tags.quote_id = _quotes.id
INNER JOIN `_topics` group by `_quotes`.`id`,`_tags`.`id`

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

trouble in find child field from primary field in mysql

I have two table like below
CREATE TABLE IF NOT EXISTS `countries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=196 ;
ANd ANother one
CREATE TABLE IF NOT EXISTS `students` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`admission_no` varchar(255) DEFAULT NULL,
`nationality_id` int(11) DEFAULT NULL,
`country_id` int(11) DEFAULT NULL,
`is_active` tinyint(1) DEFAULT '1',
`is_deleted` tinyint(1) DEFAULT '0',
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `admission_no` (`admission_no`)
) ENGINE=InnoDB DEFAULT CHARSET=latin
1 AUTO_INCREMENT=2 ;
So the problem is i want fetch both nationality_id,country_id name from countries table for this im have to use LEFT JOIN query so in this case i am facing problem as im getting same name for both if nationality_id,country_id are different as i can only join on one table only so could someone plz help me to solve this.
If I understand you correctly, you can achieve this by LEFT JOINING the same table twice, using aliases.
Something like
SELECT *
FROM students s LEF TJOIN
countries c ON s.country_id = c.id LEFT JOIN
countries n ON s.nationality_id = n.id
#astander there is a little bug in your query (second alias for countries n is not used in on statement). here is a correct statement.
select s.Id, cNationality.Name, cCountry.Name
from Students as s
left outer join Countries as cNationality on cNationality.Id = s.Nationality_id
left outer join Countries as cCountry on cCountry.Id = s.Country_id

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*).