Distinct unique value and sum others in mysql - mysql

I am trying to get the order_payment_total of the unique od_grp_id once but while using sum it get added.
CREATE TABLE IF NOT EXISTS `subscription` (
`id` int(11) unsigned NOT NULL,
`od_grp_id` int(11) unsigned NULL,
`user_id` int(11) NOT NULL,
`order_discount` decimal(10, 2) null,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8;
INSERT INTO `subscription` (
`id`, `od_grp_id`, `user_id`, `order_discount`
)
VALUES
(123994, NULL, 115, null),
(124255, NULL, 115, null),
(124703, 1647692222, 115, null),
(125788, 1647692312, 115, '25.00'),
(125789, 1647692312, 115, '5.00');
CREATE TABLE IF NOT EXISTS `online_payment_against_subscription` (
`subscription_od_grp_id` int(11) unsigned NOT NULL,
`order_payment_total` decimal(10, 2) unsigned NOT NULL,
`user_id` int(11) NOT NULL
) DEFAULT CHARSET = utf8;
INSERT INTO `online_payment_against_subscription` (
`subscription_od_grp_id`, `order_payment_total`, `user_id`
)
VALUES
(1643695200, '45.00', 115),
(1647692312, '250.00', 115),
(1647692222, '30.00', 115);
SELECT
sum(y.order_payment_total),
sum(s.order_discount)
FROM
subscription s
LEFT JOIN(
SELECT
SUM(order_payment_total) as order_payment_total,
user_id,
subscription_od_grp_id
FROM
online_payment_against_subscription
GROUP BY
subscription_od_grp_id
) y ON y.subscription_od_grp_id = s.od_grp_id
WHERE
find_in_set(
s.id, '123994,124255,124703,125788,125789'
)
group by
s.user_id
Current Output:
| sum(y.order_payment_total) |sum(s.order_discount) |
|----------------------------|-----------------------|
| 530 | 30 |
Expected Ouput:
| sum(y.order_payment_total) |sum(s.order_discount) |
|----------------------------|-----------------------|
| 280 | 30 |
Sql Fiddle: http://sqlfiddle.com/#!9/5628f5/1

If I understand correctly, The problem is caused by some duplicate od_grp_id from subscription table, so you might remove the duplicate od_grp_id before JOIN, so we might do that in a subquery.
Query 1:
SELECT
SUM(order_payment_total),
SUM(order_discount)
FROM (
SELECT od_grp_id,SUM(order_discount) order_discount
FROM subscription
WHERE find_in_set(id, '123994,124255,124703,125788,125789')
GROUP BY od_grp_id
) s
LEFT JOIN online_payment_against_subscription y ON y.subscription_od_grp_id=s.od_grp_id
Results:
| SUM(order_payment_total) | SUM(order_discount) |
|--------------------------|---------------------|
| 280 | 30 |

I think you are getting this error because every subscription doesn't have an order payment that is you are getting NULL values.
You can try to remove them by using this -
SELECT y.order_payment_total
FROM subscription s
LEFT JOIN(SELECT SUM(order_payment_total) AS order_payment_total, user_id, subscription_od_grp_id
FROM online_payment_against_subscription
GROUP BY subscription_od_grp_id) y ON y.subscription_od_grp_id = s.od_grp_id
WHERE FIND_IN_SET(s.id, '11258,22547,18586')
AND y.order_payment_total IS NOT NULL;
Or you can make NULL values 0 if you required -
SELECT COALESCE(y.order_payment_total, 0) AS order_payment_total
FROM subscription s
LEFT JOIN(SELECT SUM(order_payment_total) AS order_payment_total, user_id, subscription_od_grp_id
FROM online_payment_against_subscription
GROUP BY subscription_od_grp_id) y ON y.subscription_od_grp_id = s.od_grp_id
WHERE FIND_IN_SET(s.id, '11258,22547,18586');

Related

Count clause -> incorrect count value

We have an issue using a counting combination with inner/left join that we cannot figure out how to solve.
We would appreciate any help on the matter!
We have 4 tables in the example:
1: providers: Including 2 providers
2: providers_categories: Including 2 categories. 1 provider can be in multiple categories (this seems to be causing the issue)
3: connections_providers: connecting the providers to the categories
4: reviews_providers: currently we have included 1 rating per provider
Goal: to output the review count from the table reviews_providers.
Issue: Provider 2 is included in 2 categories. The review count is doubled: 1 count for each provider category: A total of 2 reviews are printed even though only 1 entry exists.
Thank you!
Code:
SELECT prov.id, prov.title, prov_cat.title AS category, AVG(reviews.rating) AS rating, COUNT(reviews.rating) AS count
FROM connections_providers_categories conn
INNER JOIN providers_categories prov_cat
ON prov_cat.id = conn.category_id
LEFT JOIN reviews_providers reviews
ON reviews.provider_id = conn.provider_id
INNER JOIN providers prov
ON prov.id = conn.provider_id
GROUP BY prov.id
ORDER BY prov.title ASC
CREATE TABLE `connections_providers_categories` (
`provider_id` int(4) UNSIGNED NOT NULL,
`category_id` int(4) UNSIGNED NOT NULL
) ENGINE=MyISAM DEFAULT;
INSERT INTO `connections_providers_categories` (`provider_id`, `category_id`) VALUES
(1, 1),
(2, 1),
(2, 2);
CREATE TABLE `providers` (
`id` int(4) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT;
INSERT INTO `providers` (`id`, `title`) VALUES
(1, 'Provider 1'),
(2, 'Provider 2');
CREATE TABLE `providers_categories` (
`id` int(4) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(60) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT;
INSERT INTO `providers_categories` (`id`, `title`) VALUES
(1, 'Category 1'),
(2, 'Category 2');
CREATE TABLE `reviews_providers` (
`id` int(4) UNSIGNED NOT NULL AUTO_INCREMENT,
`provider_id` int(4) UNSIGNED NOT NULL,
`rating` enum('1','2','3','4','5') DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT;
INSERT INTO `reviews_providers` (`id`, `provider_id`, `rating`) VALUES
(1, 2, '5'),
(2, 1, '3');
Our question might resemble the following question, but we do not find the answer / see that it is the same case even thought both questions include multiple counts: count is multiplied after adding left join
It seems we might need a subquery, but we are not sure how to do this.
Any suggestions?
Thanks!
you can use subquery top get your result
SELECT prov.id, prov.title, GROUP_CONCAT(prov_cat.title) AS category, reviews.rating , reviews.count
FROM connections_providers_categories conn
INNER JOIN providers_categories prov_cat
ON prov_cat.id = conn.category_id
LEFT JOIN (SELECT provider_id, AVG(rating) AS rating, COUNT(provider_id) AS count FROM reviews_providers GROUP BY provider_id) reviews
ON reviews.provider_id = conn.provider_id
INNER JOIN providers prov
ON prov.id = conn.provider_id
GROUP BY prov.id,prov.title
ORDER BY prov.title ASC
id | title | category | rating | count
-: | :--------- | :-------------------- | -----: | ----:
1 | Provider 1 | Category 1 | 3 | 1
2 | Provider 2 | Category 2,Category 1 | 5 | 1
db<>fiddle here

MySQL LEFT JOIN with one column in ON clause

Having a query that needs to be optimized, the query looks like below:
SELECT *
FROM TableA
LEFT JOIN TableB ON TableA.column_1 = TableB.column_1
AND TableB.column_2 IS NOT NULL
AND TableB.column_3 IS NULL
AND TableB.column_4 IS NULL
AND TableB.column_5 IS NULL
LEFT JOIN TableC ON TableA.column_1 = TableC.column_1
AND TableC.column_3 IS NULL
AND TableC.column_4 IS NULL
AND TableC.column_5 IS NULL
The slow part in a query is a lot of IS NULL in ON clause. The time execution is around 4+ seconds. After playing with the query for a while i've noticed that IS NULL can be omitted from the fields in ON clause. Like so:
SELECT *
FROM TableA
LEFT JOIN TableB ON TableA.column_1 = TableB.column_1
AND TableB.column_2 IS NOT NULL
AND TableB.column_3
AND TableB.column_4
AND TableB.column_5
LEFT JOIN TableC ON TableA.column_1 = TableC.column_1
AND TableC.column_3
AND TableC.column_4
AND TableC.column_5
The time execution for this query is 53ms!, and the set of records is also the same as we have from the first query. Tried to google it and didn't find anything.
Does anyone know how it works?
MySQL version is 5.7.25
UPDATE
CREATE TABLE TableA (
`column_1` INT(2) NOT NULL,
`column_2` datetime NULL,
`column_3` datetime NULL,
`column_4` datetime NULL,
`column_5` datetime NULL,
)
CREATE TABLE TableB (
`column_1` INT(2) NOT NULL,
`column_2` datetime NULL,
`column_3` datetime NULL,
`column_4` datetime NULL,
`column_5` datetime NULL,
)
CREATE TABLE TableC (
`column_1` INT(2) NOT NULL,
`column_2` datetime NULL,
`column_3` datetime NULL,
`column_4` datetime NULL,
`column_5` datetime NULL,
)
INSERT INTO `TableA` (`column_1`, `column_2`, `column_3`, `column_4`, `column_5`)
VALUES
(1, '2019-08-13 00:00:00', NULL, NULL, NULL);
Didn't include indexes, but each field which is used in ON clause has index
Consider the table:
create table tablename (id int, col datetime);
insert into tablename (id, col) values
(5, null),
(6, '2019-01-06 11:38:41'),
(7, '2019-01-06 11:39:40'),
(8, '2019-01-06 11:39:49');
The query:
select *
from tablename
where col
returns:
| id | col |
| --- | ------------------- |
| 6 | 2019-01-06 11:38:41 |
| 7 | 2019-01-06 11:39:40 |
| 8 | 2019-01-06 11:39:49 |
See the demo.
Meaning that in order to evaluate col as a value of 0 (False) or 1 (True), since the evaluation takes place in the WHERE clause, MySql converts any non null datetime value to a positive number >0, evaluating to True and any null value will evaluate to not True (so treated like False) .
What you describe is the exact opposite.
Because TableB.column_3 IS NULL and just TableB.column_3 when evaluated as >0 or 0 in a WHERE or ON clause return the opposite results.

Lahman's Baseball Database - Determine Primary Position

I'm using Lahman's Baseball Database and MySQL to determine each player's primary position. The goal is to write a query that will return the playerID and the position at which they played most games. I know that I would probably want a query that looks something like this:
select playerID, sum(G)
from fielding
where POS = 'C'
group by playerID
order by sum(G) desc;
The above query gathers all the games each player has played as a catcher. What I want to do is take each player and compare the sum of games played at each position and find the maximum value from that.
If you are not familiar with Lahman's Baseball Database here is the download link: http://www.seanlahman.com/baseball-archive/statistics/
Also here is the create table statement for the Fielding table:
CREATE TABLE `Fielding` (
`playerID` varchar(9) NOT NULL DEFAULT '',
`yearID` int(11) NOT NULL DEFAULT '0',
`stint` int(11) NOT NULL DEFAULT '0',
`teamID` varchar(3) DEFAULT NULL,
`lgID` varchar(2) DEFAULT NULL,
`POS` varchar(2) NOT NULL DEFAULT '',
`G` int(11) DEFAULT NULL,
`GS` int(11) DEFAULT NULL,
`InnOuts` int(11) DEFAULT NULL,
`PO` int(11) DEFAULT NULL,
`A` int(11) DEFAULT NULL,
`E` int(11) DEFAULT NULL,
`DP` int(11) DEFAULT NULL,
`PB` int(11) DEFAULT NULL,
`WP` int(11) DEFAULT NULL,
`SB` int(11) DEFAULT NULL,
`CS` int(11) DEFAULT NULL,
`ZR` double DEFAULT NULL,
PRIMARY KEY (`playerID`,`yearID`,`stint`,`POS`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The Fielding table is organized by year. POS is the position, G is for the number of games they played at the that position in the corresponding year. That means there will be multiple entires for some players in the same year. Also, ignore the case when POS = 'OF' as this takes the sum of all games played at LF, CF, and RF in the given year.
The final output should be a row for each distinct player, with columns playerID and primaryPosition.
plan
create table showing sums of players in all positions
get maximum sum of positions from this table
join back to sums to get the corresponding primary position
query
create table psums as
(
select playerID, POS, sum(G) as sm
from Fielding
where POS <> 'OF'
group by playerID, POS
)
;
select ps.playerID, ps.POS as primaryPosition
from
(
select playerID, max(sm) mx
from psums
group by playerID
) maxs
inner join
psums ps
on maxs.playerID = ps.playerID
and maxs.mx = ps.sm
order by ps.playerID
;
[ adding limit 10 ]
output
+-----------+-----------------+
| playerID | primaryPosition |
+-----------+-----------------+
| aardsda01 | P |
| aaronha01 | RF |
| aaronto01 | 1B |
| aasedo01 | P |
| abadan01 | 1B |
| abadfe01 | P |
| abadijo01 | 1B |
| abbated01 | 2B |
| abbeybe01 | P |
| abbeych01 | P |
+-----------+-----------------+
SELECT x.*
FROM fielding x
JOIN
(
SELECT playerid
, MAX(g) max_g
FROM fielding
GROUP
BY playerid
) y
ON y.playerid = x.playerid
AND y.max_g = x.g
LIMIT 10;
...or, more likely...
SELECT x.*
FROM
( SELECT playerid,pos,SUM(g) sum_g FROM fielding GROUP BY playerid,pos ) x
JOIN
(
SELECT playerid
, MAX(sum_g) max_sum_g
FROM
( SELECT playerid
, pos
, SUM(g) sum_g
FROM fielding
GROUP
BY playerid
, pos
) n
GROUP
BY playerid
) y
ON y.playerid = x.playerid
AND y.max_sum_g = x.sum_g
LIMIT 10;

MySQL ORDER BY strange sorting

Problem: mysql query return results in strange order, looks like random or so. But it happens only with one hosting, localhost and another one hosting working well. Wanna get - why it happens and how to prevent it.
Schema:
CREATE TABLE `product` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`sort_order` int(11) NOT NULL DEFAULT '0',
`status` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
insert into product (sort_order, status)
values
(0, 1),
(0, 1),
(0, 1),
(0, 1),
(0, 1);
CREATE TABLE `product_description` (
`product_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`product_id`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
insert into product_description
values
(1, 'product_1'),
(2, 'product_2'),
(3, 'product_3'),
(4, 'product_4'),
(5, 'product_5');
CREATE TABLE `product_to_category` (
`product_id` int(11) NOT NULL,
`product_category_id` int(11) NOT NULL,
PRIMARY KEY (`product_id`,`product_category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
insert into product_to_category
values
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);
CREATE TABLE `product_category_path` (
`product_category_id` int(11) NOT NULL,
`path_id` int(11) NOT NULL,
`level` int(11) NOT NULL,
PRIMARY KEY (`product_category_id`,`path_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
insert into product_category_path values (1, 1, 0);
Query:
SELECT p.product_id, pc.product_category_id, pd.name
FROM `product` p
LEFT JOIN `product_description` pd ON pd.product_id = p.product_id
LEFT JOIN `product_to_category` pc ON pc.product_id = p.product_id
WHERE p.status = 1 AND pc.product_category_id IN (SELECT product_category_id FROM `product_category_path` WHERE path_id = 1)
ORDER BY p.sort_order ASC;
On localhost and hosting result is always the same: 1,2,3,4,5. But on hosting it shows 1,3,2,5,4 or 2,1,5,3,4 and everytime new ordering. Why?
Update
http://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html
http://s.petrunia.net/blog/?p=24
SQL systems (of any make and model) are allowed to return result set rows in any order they find convenient unless you specify the order specifically. To put it another way, the order of a result set is formally unpredictable unless it's specified in ORDER BY. To put it a third way, on your localhost server, it's entirely accidental that your results are in the order you think they should be in. Tables have no inherent order.
You are really lucky your production server exposed this flaw in your query so quickly. Often developers don't find out about this stuff until their tables grow to tens of thousands of rows.
As this modification of your query shows (http://sqlfiddle.com/#!2/211536/2/0), all rows in your resultset have the same value of SORT_ORDER.
Query:
SELECT p.sort_order, p.product_id, pc.product_category_id, pd.name
FROM `product` p
LEFT JOIN `product_description` pd ON pd.product_id = p.product_id
LEFT JOIN `product_to_category` pc ON pc.product_id = p.product_id
WHERE p.status = 1 AND pc.product_category_id IN (SELECT product_category_id FROM `product_category_path` WHERE path_id = 1)
ORDER BY p.sort_order ASC
Results:
| SORT_ORDER | PRODUCT_ID | PRODUCT_CATEGORY_ID | NAME |
|------------|------------|---------------------|-----------|
| 0 | 1 | 1 | product_1 |
| 0 | 2 | 1 | product_2 |
| 0 | 3 | 1 | product_3 |
| 0 | 4 | 1 | product_4 |
| 0 | 5 | 1 | product_5 |
You've told SQL to order them that way. Both servers have done so.
If you need them to be ordered by PRODUCT_ID as well as SORT_ORDER just specify it (http://sqlfiddle.com/#!2/211536/4/0).
ORDER BY p.sort_order ASC, p.product_id ASC;

MySQL Bug LIMIT in JOIN-Query change values in records

in the following scenario:
CREATE TABLE `table1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`text1` varchar(29) NOT NULL,
`flag` bit(1) DEFAULT NULL,
`reference` int(11) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE ,
UNIQUE KEY `idx_text` (`text1`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `table1` (id, text1, flag, reference) VALUES
(31486, 'YWXH-D6N4-XXH6', 0, NULL),
(31487, 'CBH0-UJBC-MFTO', 0, NULL),
(31488, 'FRQM-E6MW-6VFE', 1, 1657),
(31489, 'LZOS-EYDT-1BBF', 0, NULL),
(31490, 'D1XQ-YKAX-XQRC', 0, NULL);
CREATE TABLE `table2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`value1` int(11) NOT NULL,
`value2` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `value1` (`value1`),
KEY `value2` (`value2`)
) ENGINE=MyISAM AUTO_INCREMENT=20068 DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED;
INSERT INTO table2 (id, value1, value2) VALUES
(1657, 1891, 1748);
-- the tables are shortened from "real" tables, i used SHOW CREATE <table> to create this script.
are the results of the following queries different.
here mysql returns for the record with id 31488 and 31490 the wrong value for the bit-field:
Query 1:
SELECT m.id, m.text1, m.flag, m.reference
FROM table1 AS m LEFT JOIN table2 AS v ON v.id = m.reference
GROUP BY m.text1 ORDER BY m.text1 DESC LIMIT 0, 5;
returns the correct result:
id | text1 | flag | reference
31487 | CBH0-UJBC-MFTO | 0 | NULL
31490 | D1XQ-YKAX-XQRC | 0 | NULL
31488 | FRQM-E6MW-6VFE | 1 | 1657
31489 | LZOS-EYDT-1BBF | 0 | NULL
31486 | YWXH-D6N4-XXH6 | 0 | NULL
while Query 2
SELECT m.id, m.text1, m.flag, m.reference
FROM table1 AS m LEFT JOIN table2 AS v ON v.id = m.reference
GROUP BY m.text1 ORDER BY m.text1 DESC LIMIT 0, 4;
returns this:
id | text1 | flag | reference
31487 | CBH0-UJBC-MFTO | 0 | NULL
31490 | D1XQ-YKAX-XQRC | 1 | NULL
31488 | FRQM-E6MW-6VFE | 0 | 1657
31489 | LZOS-EYDT-1BBF | 0 | NULL
so here is my question:
Im using Joomla CMS, and in the code of the component i can change the whole query except the LIMIT-part.
Joomla add the limit part to the query because of the pagination.
Is there a way to change the query that it works with the LIMIT-command?
oh, my MySQL-Version on Server is 5.1.61 (but this bug still exists on my client v5.5.16)
Your a) not inserting the data correctly - see the BIT data type docs and b) not selecting the data correctly - see the docs on the Bit-Field Literals
You need to insert using the following syntax
INSERT INTO `table1` (id, text1, flag, reference) VALUES
(31486, 'YWXH-D6N4-XXH6', b'0', NULL),
(31487, 'CBH0-UJBC-MFTO', b'0', NULL),
(31488, 'FRQM-E6MW-6VFE', b'1', 1657),
(31489, 'LZOS-EYDT-1BBF', b'0', NULL),
(31490, 'D1XQ-YKAX-XQRC', b'0', NULL);
Then select like this :
SELECT m.id, m.text1, bin(m.flag), m.reference
FROM table1 AS m LEFT JOIN table2 AS v ON v.id = m.reference
GROUP BY m.text1 ORDER BY m.text1 DESC LIMIT 0, 4;
Then it all works as expected