Having problems with getting a count in a select statement - mysql

I have 5 tables as follows:
files
tags
profiles
j_file_tags
j_profile_tags
So files can have tags, profiles give access to certain tags.
I put together two queries that do the following:
get a list of files that a specific profile has access to (the profile must have access to all tags a file might have)
get a list of tags that the profile has access to and where there is at least a file in that tag.
What I need for query 2 is a count of how many files are in a tag.
Here's the table structure and sample data:
CREATE TABLE `files` (
`id` int(4) NOT NULL AUTO_INCREMENT ,
`fileName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`empID` int(4) NOT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=Dynamic;
CREATE TABLE `j_file_tags` (
`id` int(4) NOT NULL AUTO_INCREMENT ,
`fileID` int(4) NULL DEFAULT NULL ,
`tagID` int(4) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=Dynamic;
CREATE TABLE `j_profile_tags` (
`id` int(4) NOT NULL AUTO_INCREMENT ,
`profileID` int(4) NULL DEFAULT NULL ,
`tagID` int(4) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=Dynamic;
CREATE TABLE `profiles` (
`id` int(4) NOT NULL AUTO_INCREMENT ,
`profileName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=Dynamic;
CREATE TABLE `tags` (
`id` int(4) NOT NULL AUTO_INCREMENT ,
`tagName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=Dynamic;
INSERT INTO `files` VALUES ('1', 'FileOne', '1');
INSERT INTO `files` VALUES ('2', 'FileTwo', '1');
INSERT INTO `files` VALUES ('3', 'FileThree', '1');
INSERT INTO `files` VALUES ('4', 'FileFour', '2');
INSERT INTO `files` VALUES ('5', 'FileFive', '2');
INSERT INTO `files` VALUES ('6', 'FileSix', '2');
INSERT INTO `files` VALUES ('7', 'FileSeven', '2');
INSERT INTO `profiles` VALUES ('1', 'ProfileOne');
INSERT INTO `profiles` VALUES ('2', 'ProfileTwo');
INSERT INTO `profiles` VALUES ('3', 'ProfileThree');
INSERT INTO `tags` VALUES ('1', 'TagOne');
INSERT INTO `tags` VALUES ('2', 'TagTwo');
INSERT INTO `tags` VALUES ('3', 'TagThree');
INSERT INTO `tags` VALUES ('4', 'TagFour');
INSERT INTO `tags` VALUES ('5', 'TagFive');
INSERT INTO `j_file_tags` VALUES ('1', '1', '1');
INSERT INTO `j_file_tags` VALUES ('2', '1', '3');
INSERT INTO `j_file_tags` VALUES ('3', '2', '1');
INSERT INTO `j_file_tags` VALUES ('4', '2', '5');
INSERT INTO `j_file_tags` VALUES ('5', '3', '1');
INSERT INTO `j_file_tags` VALUES ('6', '3', '3');
INSERT INTO `j_file_tags` VALUES ('7', '3', '6');
INSERT INTO `j_file_tags` VALUES ('8', '2', '3');
INSERT INTO `j_file_tags` VALUES ('9', '4', '1');
INSERT INTO `j_file_tags` VALUES ('10', '4', '2');
INSERT INTO `j_file_tags` VALUES ('11', '5', '1');
INSERT INTO `j_file_tags` VALUES ('12', '5', '6');
INSERT INTO `j_profile_tags` VALUES ('1', '1', '2');
INSERT INTO `j_profile_tags` VALUES ('2', '1', '3');
INSERT INTO `j_profile_tags` VALUES ('3', '1', '4');
INSERT INTO `j_profile_tags` VALUES ('4', '2', '1');
INSERT INTO `j_profile_tags` VALUES ('5', '2', '2');
INSERT INTO `j_profile_tags` VALUES ('6', '2', '3');
INSERT INTO `j_profile_tags` VALUES ('7', '2', '4');
INSERT INTO `j_profile_tags` VALUES ('8', '2', '5');
INSERT INTO `j_profile_tags` VALUES ('9', '1', '1');
INSERT INTO `j_profile_tags` VALUES ('10', '1', '5');
Here are my 2 queries:
/* Get list of files: limit by specific employee AND by tags the use has access to */
SELECT
`files`.`id`,
`files`.`fileName`,
`files`.`empID`,
GROUP_CONCAT(CONCAT(`tags`.`id`) SEPARATOR ', ') as `FileTags`
FROM `files`
LEFT JOIN `j_file_tags` ON `j_file_tags`.`fileID` = `files`.`id`
LEFT JOIN `tags` ON `tags`.`id` = `j_file_tags`.`tagID`
WHERE
`files`.`empID` = 1
AND
`j_file_tags`.`tagID` IN (1,2,3,4,5)
GROUP BY
`files`.`id`
HAVING
COUNT(`j_file_tags`.`id`) = (SELECT COUNT(`j_file_tags`.`id`) FROM `j_file_tags` WHERE `j_file_tags`.`fileID` = `files`.`id` );
/* SECOND QUERY where i need help */
SELECT
`tags`.`id`,
`tags`.`tagName`,
'1' as `fileCount` /* i need this to be an actual count */
FROM
`tags`
LEFT JOIN `j_file_tags` ON `j_file_tags`.`tagID` = `tags`.`id`
LEFT JOIN `files` ON `files`.`id` = `j_file_tags`.`fileID`
LEFT JOIN `j_profile_tags` ON `j_profile_tags`.`tagID` = `tags`.`id`
WHERE
`j_profile_tags`.`profileID` = 1
AND
`files`.`empID` = 1
GROUP BY
`tags`.`id`;
/* the fileCount column would need to say for TagOne - 2, for TagThree - 2 and for TagFive - 1 */
In the sample data the first query returns:
| 1 | FileOne | 1 | 1, 3
| 2 | FileTwo | 1 | 3, 1, 5
The second query returns:
| 1 | TagOne | should return 2
| 3 | TagThree | should return 2
| 5 | TagFive| | should return 1

The answer is simple the HAVING clause that you have in the first query is throwing off your results because there are truly 3 files with tags 1 and 3. I would suggest removing it all together or figuring out another way to do it. I rewrote your query below to display your desired result, however it is not a fix all.
SELECT
tags.id,
tags.tagName,
count(fileID) as 'fileCount'
FROM files
LEFT JOIN j_file_tags ON j_file_tags.fileID = files.id
LEFT JOIN tags ON tags.id = j_file_tags.tagID
WHERE
files.empID = 1
AND
j_file_tags.tagID IN (1,2,3,4,5)
AND
fileID IN (1,2)
GROUP BY
tags.id

Related

Convert MariaDb query into MySQL

I have query in mariaDB, this query is used to (get ancestors of a child (dog) upto Level 5)
WITH RECURSIVE
cte AS (
SELECT *, 0 level, ' ' relation
FROM dogs
WHERE dog_id = 7
UNION ALL
SELECT dogs.*, level + 1, 'father'
FROM dogs
JOIN cte ON cte.father_id = dogs.dog_id
WHERE level < 5
UNION ALL
SELECT dogs.*, level + 1, 'mother'
FROM dogs
JOIN cte ON cte.mother_id = dogs.dog_id
WHERE level < 5
)
SELECT *
FROM cte
ORDER BY level, relation;
I want this query in mysql version: 5.6.45
Here is Table Script:
CREATE TABLE `dogs` (
`dog_id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`father_id` int(11) DEFAULT NULL,
`mother_id` int(11) DEFAULT NULL,
PRIMARY KEY (`dog_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `dogs` VALUES ('0', null, null, null);
INSERT INTO `dogs` VALUES ('1', 'Father', null, null);
INSERT INTO `dogs` VALUES ('2', 'Mother', null, null);
INSERT INTO `dogs` VALUES ('3', 'Father1', null, null);
INSERT INTO `dogs` VALUES ('4', 'Mother2', null, null);
INSERT INTO `dogs` VALUES ('5', 'Son', '1', '2');
INSERT INTO `dogs` VALUES ('6', 'Daughter', '3', '4');
INSERT INTO `dogs` VALUES ('7', 'GrandSon', '5', '6');

Show filters from category & products, show filters relevant filter post selection (and non-relevant from active parent) & product count per filter

I posted a similar question on 10 Jan 2020 (see here) but my problem/question has expanded since then and don't want S.O. police on my back ;)
This is the criteria:
There are filter categories and there are filters belong to those categories.
Each filter displays a count of how many products belong to a filter.
The number of available filters need to reduce depending on active filter selection to not only those that still apply to the pool of products but those that are also relevant to child filters of other filter categories.
There is a caveat to the above, if only one filter category has child filters selected then all the sibling filters (filters of the same filter category are to still display) until a filter from another filter category is made active. Once a filter from another filter category/parent is selected the previous full list can reduce but previously select filters must remain active just show a count of zero if that's the case.
I think I'm really close with the SQL below but it will not correctly update the count of products belonging to each filter upon selection. The only way I can get it to work is if I change the OR to an AND in the SQL below but this then will not show the other child filters belonging to a filter category that has an active child filter.
I have provided schema and sample data here, along with a fiddle of samehttp://sqlfiddle.com/#!9/afbd4d7/1/0:
CREATE TABLE `store_categories` (
`categories_id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`categories_id`),
KEY `idx_categories_parent_id` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `store_products` (
`products_id` int(11) NOT NULL AUTO_INCREMENT,
`products_status` tinyint(1) NOT NULL,
PRIMARY KEY (`products_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `store_products_filters` (
`pf_id` int(11) NOT NULL AUTO_INCREMENT,
`pf_name` varchar(250) COLLATE utf8_unicode_ci DEFAULT NULL,
`pf_sort` int(4) DEFAULT '0',
`pf_to_pfc_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`pf_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `store_products_filters_categories` (
`pfc_id` int(11) NOT NULL AUTO_INCREMENT,
`pfc_name` varchar(250) COLLATE utf8_unicode_ci DEFAULT NULL,
`pfc_sort` int(4) DEFAULT '0',
PRIMARY KEY (`pfc_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `store_products_filters_to_products` (
`pftp_id` int(11) NOT NULL AUTO_INCREMENT,
`pftp_pf_id` int(11) DEFAULT NULL,
`pftp_products_id` int(11) DEFAULT NULL,
PRIMARY KEY (`pftp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `store_products_to_categories` (
`products_id` int(11) NOT NULL,
`categories_id` int(11) NOT NULL,
PRIMARY KEY (`products_id`,`categories_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `store_categories` VALUES ('1', '0');
INSERT INTO `store_categories` VALUES ('2', '1');
INSERT INTO `store_categories` VALUES ('3', '0');
INSERT INTO `store_categories` VALUES ('4', '1');
INSERT INTO `store_categories` VALUES ('5', '0');
INSERT INTO `store_categories` VALUES ('6', '0');
INSERT INTO `store_products` VALUES ('1', '1');
INSERT INTO `store_products` VALUES ('2', '1');
INSERT INTO `store_products` VALUES ('3', '1');
INSERT INTO `store_products` VALUES ('4', '1');
INSERT INTO `store_products` VALUES ('5', '0');
INSERT INTO `store_products_filters` VALUES ('1', 'Small', '0', '1');
INSERT INTO `store_products_filters` VALUES ('2', 'Medium', '0', '1');
INSERT INTO `store_products_filters` VALUES ('3', 'Large', '0', '1');
INSERT INTO `store_products_filters` VALUES ('4', 'Extra Large', '0', '1');
INSERT INTO `store_products_filters` VALUES ('5', 'Circle', '0', '2');
INSERT INTO `store_products_filters` VALUES ('6', 'Square', '0', '2');
INSERT INTO `store_products_filters` VALUES ('7', 'Triangle', '0', '2');
INSERT INTO `store_products_filters` VALUES ('8', 'Red', '5000', '3');
INSERT INTO `store_products_filters` VALUES ('9', 'Blue', '5000', '3');
INSERT INTO `store_products_filters` VALUES ('10', 'Black', '2000', '3');
INSERT INTO `store_products_filters` VALUES ('11', 'Yellow', '5000', '3');
INSERT INTO `store_products_filters_categories` VALUES ('1', 'Size', '300');
INSERT INTO `store_products_filters_categories` VALUES ('2', 'Type', '100');
INSERT INTO `store_products_filters_categories` VALUES ('3', 'Colour', '400');
INSERT INTO `store_products_filters_to_products` VALUES ('1', '1', '1');
INSERT INTO `store_products_filters_to_products` VALUES ('2', '6', '1');
INSERT INTO `store_products_filters_to_products` VALUES ('3', '9', '1');
INSERT INTO `store_products_filters_to_products` VALUES ('4', '1', '2');
INSERT INTO `store_products_filters_to_products` VALUES ('5', '5', '2');
INSERT INTO `store_products_filters_to_products` VALUES ('6', '8', '2');
INSERT INTO `store_products_filters_to_products` VALUES ('7', '2', '3');
INSERT INTO `store_products_filters_to_products` VALUES ('8', '7', '3');
INSERT INTO `store_products_filters_to_products` VALUES ('9', '11', '3');
INSERT INTO `store_products_filters_to_products` VALUES ('10', '3', '4');
INSERT INTO `store_products_filters_to_products` VALUES ('11', '5', '4');
INSERT INTO `store_products_filters_to_products` VALUES ('12', '10', '4');
INSERT INTO `store_products_to_categories` VALUES ('1', '2');
INSERT INTO `store_products_to_categories` VALUES ('2', '2');
INSERT INTO `store_products_to_categories` VALUES ('3', '2');
INSERT INTO `store_products_to_categories` VALUES ('4', '2');
INSERT INTO `store_products_to_categories` VALUES ('5', '2');
There are 3 active filters, Small, Medium and Circle.
There are 2 "Small" sized products
There is 1 "Medium" sized product
There are 2 products that have a "Circle" filter applied to them but only one of those is "Small" and the other is "Large"
With Small, Medium filters applied I would expect/like Circle to show 1 but it shows a count of 2
OR pf.pf_id IN (
SELECT
pf_id
FROM
store_products_filters
WHERE
pf_to_pfc_id IN (1, 2)
)
My thought so far is to remove the above SQL if filters from more than one filter category are active.
You can see an example of what I'm trying to achieve on this site https://www.ukpos.com/display-stands-frames-and-noticeboards which is powered by Magento. I'm not sure if the filters are out of the box or a added plugin.
My full SQL below.
SELECT
pfc.pfc_id,
pfc.pfc_name,
pf.pf_id,
pf.pf_name,
count(pftp.pftp_pf_id) AS products_in_filter
FROM
store_products_filters_to_products pftp
LEFT JOIN store_products_filters pf ON pftp.pftp_pf_id = pf.pf_id
LEFT JOIN store_products_filters_categories pfc ON pf.pf_to_pfc_id = pfc_id
WHERE
pftp_products_id IN (
SELECT
ptc.products_id
FROM
store_products_to_categories ptc
LEFT JOIN store_products p ON ptc.products_id = p.products_id
WHERE
p.products_status = 1
AND (
ptc.categories_id = 1
OR ptc.categories_id IN (
SELECT
categories_id
FROM
store_categories
WHERE
parent_id = '1'
)
)
)
AND (
pf.pf_id IN (
SELECT
pftp_pf_id
FROM
store_products_filters_categories
WHERE
pftp_products_id IN (
SELECT
pftp.pftp_products_id
FROM
store_products_filters_to_products pftp
JOIN store_products_filters pf ON pf.pf_id = pftp.pftp_pf_id
GROUP BY
pftp.pftp_products_id
HAVING
(
sum(pf.pf_id = 1) > 0
OR sum(pf.pf_id = 2) > 0
)
AND (sum(pf.pf_id = 5) > 0)
)
)
OR pf.pf_id IN (
SELECT
pf_id
FROM
store_products_filters
WHERE
pf_to_pfc_id IN (1, 2)
)
)
GROUP BY
pfc.pfc_id,
pftp.pftp_pf_id
ORDER BY
pfc.pfc_sort ASC,
pfc.pfc_name ASC,
pf.pf_sort ASC,
pf.pf_name ASC

MySQL query: Updating foreign key with unique Id

I need to link two tables 1-to-1, but the values that are to be compared and linked upon, are not unique.
I cannot find a way. As an example, I added a very simple version.
CREATE TABLE `T1` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
`uniqueT2Id` int(3) unsigned,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `T2` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `T1` (`id`, `cmp`, `uniqueT2Id`) VALUES
('1', '1', NULL),
('2', '1', NULL),
('3', '2', NULL),
('4', '3', NULL),
('5', '1', NULL);
INSERT INTO `T2` (`id`, `cmp`) VALUES
('1', '1'),
('2', '1'),
('3', '1'),
('4', '2'),
('5', '3');
UPDATE T1 SET uniqueT2Id=
(SELECT id FROM T2 WHERE T2.cmp=T1.cmp AND
id NOT IN (SELECT * FROM
(SELECT uniqueT2Id FROM T1 WHERE uniqueT2Id IS NOT NULL) X)
ORDER BY id ASC LIMIT 1);
SELECT * FROM T1;
http://sqlfiddle.com/#!9/3bab7c/2/0
The result is
id cmp uniqueT2Id
1 1 1
2 1 1
3 2 4
4 3 5
5 1 1
I want it to be
id rev uniqueT2Id
1 1 1
2 1 2
3 2 4
4 3 5
5 1 3
In the UPDATE I try to pick an Id that is not already used, but this obviously does not work. Does anyone know a way to do this in MySQL, preferrably without PHP?
I found an answer myself, with variables. It is horrible and requires a dummy field in the table, but it works. I am open for improvements.
CREATE TABLE `T1` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
`uniqueT2Id` int(3) NULL,
`dummy` varchar(200) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `T2` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `T1` (`id`, `cmp`, `uniqueT2Id`) VALUES
('1', '1', NULL),
('2', '1', NULL),
('3', '2', NULL),
('4', '5', NULL),
('5', '3', NULL),
('6', '1', NULL);
INSERT INTO `T2` (`id`, `cmp`) VALUES
('1', '1'),
('2', '1'),
('3', '1'),
('4', '2'),
('5', '3');
SET #taken = '/' ;
UPDATE T1
SET uniqueT2Id= #new:=
(SELECT id FROM T2 WHERE T2.cmp=T1.cmp AND
INSTR(#taken, CONCAT('/',id,'/')) = 0
ORDER BY id ASC LIMIT 1),
dummy=IF(#new IS NOT NULL,#taken:=CONCAT(#taken, #new, "/"),NULL);
http://sqlfiddle.com/#!9/4a61d/1/0

the group by in mysql5.7

I find the same sql run in mysql5.7 and mysql5.5 but the result is different.
the sql like this:
SELECT t2.* FROM (SELECT t1.* FROM t_user t1 ORDER BY t1.id desc) AS t2 GROUP BY t2.type;
The result in mysql5.7:
The result in mysql5.5:
the sql script like this:
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`gender` varchar(255) DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`birth` datetime DEFAULT NULL,
`is_delete` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
INSERT INTO `t_user` VALUES ('1', 'James', '0594-5397864', '0', '3', '2016-01-30 19:01:09', '1');
INSERT INTO `t_user` VALUES ('2', 'Hayes', '0594-5392419', '1', '4', '2015-12-24 11:12:27', '1');
INSERT INTO `t_user` VALUES ('3', 'Diana', '0594-5393520', '1', '5', '2016-03-21 13:03:50', '0');
INSERT INTO `t_user` VALUES ('4', 'Rajah', '0594-5399812', '1', '4', '2015-11-26 02:11:35', '0');
INSERT INTO `t_user` VALUES ('5', 'Daria', '0594-5397571', '0', '4', '2016-01-18 11:01:11', '1');
INSERT INTO `t_user` VALUES ('6', 'Lee', '0594-5394539', '1', '1', '2015-10-23 08:10:23', '1');
INSERT INTO `t_user` VALUES ('7', 'Cameran', '0594-5392867', '0', '4', '2016-11-16 12:11:08', '0');
INSERT INTO `t_user` VALUES ('8', 'Wylie', '0594-5395349', '0', '5', '2017-07-06 04:07:27', '0');
INSERT INTO `t_user` VALUES ('9', 'Bertha', '0594-5395287', '1', '1', '2017-02-08 12:02:45', '1');
INSERT INTO `t_user` VALUES ('10', 'Fletcher', '0594-5399246', '0', '4', '2015-09-03 20:09:33', '0');
INSERT INTO `t_user` VALUES ('11', 'Conan', '0594-5391546', '1', '5', '2017-05-15 09:05:23', '0');
INSERT INTO `t_user` VALUES ('12', 'Raymond', '0594-5399666', '0', '3', '2015-10-20 05:10:05', '1');
INSERT INTO `t_user` VALUES ('13', 'Noel', '0594-5397392', '1', '4', '2017-05-26 03:05:56', '0');
INSERT INTO `t_user` VALUES ('14', 'Miriam', '0594-5399081', '0', '2', '2016-05-21 02:05:09', '0');
INSERT INTO `t_user` VALUES ('15', 'Maya', '0594-5397242', '0', '3', '2016-10-24 02:10:50', '1');
INSERT INTO `t_user` VALUES ('16', 'Winifred', '0594-5395142', '1', '1', '2017-03-15 02:03:43', '0');
INSERT INTO `t_user` VALUES ('17', 'Elaine', '0594-5398478', '1', '3', '2017-03-08 15:03:03', '1');
INSERT INTO `t_user` VALUES ('18', 'Robert', '0594-5397830', '0', '5', '2016-02-10 22:02:06', '0');
INSERT INTO `t_user` VALUES ('19', 'Patrick', '0594-5396516', '0', '4', '2015-09-10 07:09:51', '0');
INSERT INTO `t_user` VALUES ('20', 'Darrel', '0594-5397417', '0', '1', '2016-03-11 11:03:36', '0');
INSERT INTO `t_user` VALUES ('21', 'Salvador', '0594-5399732', '1', '3', '2016-01-01 15:01:21', '0');
INSERT INTO `t_user` VALUES ('22', 'Brandon', '0594-5396204', '1', '4', '2016-05-12 06:05:40', '1');
INSERT INTO `t_user` VALUES ('23', 'Dorothy', '0594-5396783', '0', '1', '2016-12-12 10:12:59', '1');
INSERT INTO `t_user` VALUES ('24', 'Kevyn', '0594-5398240', '0', '2', '2016-02-07 04:02:14', '1');
INSERT INTO `t_user` VALUES ('25', 'Brody', '0594-5398774', '1', '1', '2016-12-11 20:12:36', '0');
what cause this different... my English is poor,LOL...
MySQL is too liberal when it comes to data integrity and its default settings often allow you to accomplish data loss without a complaint (see reference for ONLY_FULL_GROUP_BY SQL mode). For instance, it allows incomplete GROUP BY clauses like yours and just picks an arbitrary (not even random) result.
You need to rewrite your query so all columns involved fit into one category:
Be part of an aggregate expression in the SELECT clause:
SELECT MAX(foo) AS maximum_foo
Be part of the GROUP BY clause:
SELECT foo
...
GROUP BY foo
This way you are being specific enough so the result-set is deterministic. Your current code is basically: "Give me one user of each type"—but you don't specify any criteria to pick users. Other DBMSs (Oracle, SQL Server) will complaint: "You didn't say how to choose users". MySQL will merely pick an arbitrary user (but not even a random user, because randomness would imply that chosen users follow a rule, which is not the case). The ONLY_FULL_GROUP_BY SQL mode is just a way to make MySQL behave like other engines.
You can also get rid of your subquery, it really serves no purpose.
No order on outer SELECT causes the difference. However what do you want to achieve? Take only one (which one) from each group (type) or what?
SELECT *
FROM t_user
WHERE id IN (SELECT MAX(id) FROM t_user GROUP BY type)
ORDER BY type
SQL fiddle link

Why do these queries yield different results in MySQL 5.5 vs 5.6?

Can someone explain why these two queries (one using IN and one using EXISTS) return different results in MySQL 5.6 but not in MySQL 5.5?
Using EXPLAIN, I can see different execution plans for each, but I need help understanding what's going on, and why would this IN logic be broken in 5.6 but not 5.5?
Fiddle illustrating the problem: http://sqlfiddle.com/#!9/da52b/95
Members can have two addresses: a home address and a firm address. The desired result is to provide a region X and get a list of all members with a mailing address in that region. The mailing address is the firm address if it exists, otherwise it is the home address. Cities can belong to one or more regions.
Simplified database structure and data:
CREATE TABLE `city` (
`c_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`c_name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`c_id`)
);
INSERT INTO `city`
VALUES
('1', 'Hillsdale'),
('2', 'Smallville'),
('3', 'Oakside'),
('4', 'Lakeview');
CREATE TABLE `city_region` (
`cr_city` int(11) unsigned NOT NULL,
`cr_region` int(11) NOT NULL,
PRIMARY KEY (`cr_city`,`cr_region`)
);
INSERT INTO `city_region`
VALUES
('1', '3'),
('2', '1'),
('3', '1'),
('3', '2'),
('4', '1'),
('4', '3');
CREATE TABLE `firm_address` (
`fa_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`fa_member` int(11) NOT NULL,
`fa_city` int(11) NOT NULL,
PRIMARY KEY (`fa_id`)
);
INSERT INTO `firm_address`
VALUES
('1', '1', '3'),
('2', '2', '2'),
('3', '3', '1'),
('4', '6', '2'),
('5', '7', '1');
CREATE TABLE `home_address` (
`ha_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ha_member` int(11) NOT NULL,
`ha_city` int(11) NOT NULL,
PRIMARY KEY (`ha_id`)
);
INSERT INTO `home_address`
VALUES
('1', '1', '2'),
('2', '2', '3'),
('3', '3', '1'),
('4', '4', '1'),
('5', '5', '2'),
('6', '6', '2');
CREATE TABLE `member` (
`m_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`m_name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`m_id`)
);
INSERT INTO `member`
VALUES
('1', 'John'),
('2', 'Bob'),
('3', 'Dave'),
('4', 'Jane'),
('5', 'Mary'),
('6', 'Karen'),
('7', 'Christie');
CREATE TABLE `region` (
`r_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`r_name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`r_id`)
);
INSERT INTO `region`
VALUES
('1', 'Central'),
('2', 'Lake District'),
('3', 'Westside');
Query 1 (wrong, missing a member):
SELECT * FROM member
LEFT OUTER JOIN home_address ON m_id = ha_member
LEFT OUTER JOIN city home_city ON ha_city = home_city.c_id
LEFT OUTER JOIN firm_address ON m_id = fa_member
LEFT OUTER JOIN city firm_city ON fa_city = firm_city.c_id
WHERE 1 IN (
SELECT r_id
FROM region
INNER JOIN city_region ON r_id = cr_region
WHERE cr_city = IF(fa_city IS NULL, ha_city, fa_city)
)
Query 2 (returning the correct results):
SELECT * FROM member
LEFT OUTER JOIN home_address ON m_id = ha_member
LEFT OUTER JOIN city home_city ON ha_city = home_city.c_id
LEFT OUTER JOIN firm_address ON m_id = fa_member
LEFT OUTER JOIN city firm_city ON fa_city = firm_city.c_id
WHERE EXISTS (
SELECT r_id
FROM region
INNER JOIN city_region ON r_id = cr_region
WHERE cr_city = IF(fa_city IS NULL, ha_city, fa_city)
AND r_id = 1
)
Any help understanding this inconsistency would be appreciated.
Thank you.
I spent some time looking at this today, and it appears to be a bug in MySQL 5.6. (I also tested MySQL 5.6.15 and got the same result.)
MySQL 5.6 uses some new optimizations in executing this query, but they do not seem to be responsible for the difference, as it does not help to set e.g.:
set session optimizer_switch="block_nested_loop=off";
Using IFNULL(fa_city, ha_city) instead of IF(fa_city IS NULL, ha_city, fa_city) does yield a correct result, so the bug appears to be somewhere in the processing of IF().