Mysql - Get Sum of All distinct rows based on other value - mysql

I have a table which looks like this,
+-----+--------+-------+
| num | amount | value |
+-----+--------+-------+
| 1 | 12 | 1 |
| 1 | 12 | 1 |
| 2 | 13 | 1 |
| 4 | 15 | 0 |
| 2 | 13 | 1 |
| 3 | 14 | 1 |
| 3 | 14 | 1 |
| 1 | 12 | 1 |
+-----+--------+-------+
I want to sum the 'amount' column based on distinct 'num' column where 'value' is equal to 1,
for example, after running following query,
select DISTINCT num, amount, value from test where value =1 ;
distinct 'num' based table is
+-----+--------+-------+
| num | amount | value |
+-----+--------+-------+
| 1 | 12 | 1 |
| 2 | 13 | 1 |
| 3 | 14 | 1 |
+-----+--------+-------+
so i want the final result to be
12+13+14 = 39.
one more thing is that
i cant use subquery.
because it is already part of another query as well.
here is the script of my table is
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `test`
-- ----------------------------
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`num` int(11) DEFAULT NULL,
`amount` int(11) DEFAULT NULL,
`value` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES ('1', '12', '1');
INSERT INTO `test` VALUES ('1', '12', '1');
INSERT INTO `test` VALUES ('2', '13', '1');
INSERT INTO `test` VALUES ('4', '15', '0');
INSERT INTO `test` VALUES ('2', '13', '1');
INSERT INTO `test` VALUES ('3', '14', '1');
INSERT INTO `test` VALUES ('3', '14', '1');
INSERT INTO `test` VALUES ('1', '12', '1');

You can create a temp table containing distinct values and using SUM() to calculate amount. Your query will go like:
SELECT SUM(amount)
FROM (
SELECT DISTINCT t.`num`, t.`amount`
FROM test t
WHERE t.`value`=1
) temp

select num,sum(amount)/Count(*)
from test
where value = 1
group by num
order by num

I assume that every num has the same value (if not, how should you pick one?)
so, this will work:
SELECT SUM(DISTINCT amount)
FROM test
WHERE value = 1

SELECT SUM(amount) FROM (SELECT DISTINCT num, amount, VALUE FROM test WHERE VALUE =1) AS temp ;

Please check the solution
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `test`
-- ----------------------------
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`num` int(11) DEFAULT NULL,
`amount` int(11) DEFAULT NULL,
`value` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES ('1', '12', '1');
INSERT INTO `test` VALUES ('1', '12', '1');
INSERT INTO `test` VALUES ('2', '13', '1');
INSERT INTO `test` VALUES ('4', '15', '0');
INSERT INTO `test` VALUES ('2', '13', '1');
INSERT INTO `test` VALUES ('3', '14', '1');
INSERT INTO `test` VALUES ('3', '14', '1');
INSERT INTO `test` VALUES ('1', '12', '1');
-- ----------------------------
-- Insert the result set into temp table and then use sum().
-- ----------------------------
SELECT DISTINCT `num` , `amount`
INTO #tmp
FROM test
WHERE `value` =1
SELECT * FROM #tmp
SELECT sum(`amount`) as amount FROM #tmp

Related

Inner Join table with a maximum date

Please help me.
I have 2 table Users and Diseaselogs
1 user has many diseaselogs
I want to select all users and each user must be field date in diseaselogs is max
Data example
Users
id | name | age
1 | Nam | 21
2 | Thao | 23
3 | An | 19
Diseaselogs
id | logType | userId | date
1 | positive | 1 | 2021-06-21
2 | negative | 2 | 2021-06-22
3 | pending | 1 | 2021-06-24
4 | negative | 1 | 2021-06-26
5 | negative | 2 | 2021-06-21
6 | pending | 3 | 2021-06-23
7 | negative | 1 | 2021-06-24
8 | negative | 2 | 2021-06-25
9 | pending | 3 | 2021-06-28
Expect output
id | name | logId | logType | date
1 | Nam | 4 | negative | 2021-06-26
2 | Thao | 8 | negative | 2021-06-25
3 | An | 9 | pending | 2021-06-28
As ROW_NUMBER() doesn't support lower version of mysql i.e 5.7 to downwords. So I've tried here alternatives of ROW_NUMBER().
-- MySQL (V 5.6)
SELECT u.id, u.name, tmp.logId, tmp.logType, tmp.date
FROM users u
INNER JOIN (SELECT #row_no := IF(#prev_val = t.userId, #row_no + 1, 1) AS row_number
, #prev_val := t.userId AS userId
, t.date
, t.logType
, t.id AS logId
FROM Diseaselogs t,
(SELECT #row_no := 0) x,
(SELECT #prev_val := '') y
ORDER BY t.userId, t.date DESC ) tmp
ON u.id = tmp.userId
AND tmp.row_number = 1;
Please check url http://sqlfiddle.com/#!9/741b96/16
Also if your MySQL version is 5.8 then you can apply the below query where row_number() is used.
SELECT u.id, u.name, tmp.logId, tmp.logType, tmp.date
FROM users u
INNER JOIN (SELECT ROW_NUMBER() OVER (PARTITION BY userId ORDER BY date DESC) row_number
, userId
, date
, logType
, id AS logId
FROM Diseaselogs ) tmp
ON u.id = tmp.userId
AND tmp.row_number = 1;
in mysql 8 you can use ROW_NUMBER and an INNER JOIN
in prior versions you need to use another method for rownumber
Schema (MySQL v8.0)
CREATE TABLE Diseaselogs (
`id` INTEGER,
`logType` VARCHAR(8),
`userId` INTEGER,
`date` VARCHAR(10)
);
INSERT INTO Diseaselogs
(`id`, `logType`, `userId`, `date`)
VALUES
('1', 'positive', '1', '2021-06-21'),
('2', 'negative', '2', '2021-06-22'),
('3', 'pending', '1', '2021-06-24'),
('4', 'negative', '1', '2021-06-26'),
('5', 'negative', '2', '2021-06-21'),
('6', 'pending', '3', '2021-06-23'),
('7', 'negative', '1', '2021-06-24'),
('8', 'negative', '2', '2021-06-25'),
('9', 'pending', '3', '2021-06-28');
CREATE TABLE users (
`id` INTEGER,
`name` VARCHAR(4),
`age` INTEGER
);
INSERT INTO users
(`id`, `name`, `age`)
VALUES
('1', 'Nam', '21'),
('2', 'Thao', '23'),
('3', 'An', '19');
Query #1
SELECT
u.id, `name`, t1.id,`logType`, `date`
FROM
(SELECT
id,`logType`, `userId`, `date`
, ROW_NUMBER() OVER (PARTITION BY `userId` ORDER BY `date` DESC) rn
FROM
Diseaselogs) t1
INNER JOIN users u ON t1.userId = u.id
WHERE rn = 1;
id
name
id
logType
date
1
Nam
4
negative
2021-06-26
2
Thao
8
negative
2021-06-25
3
An
9
pending
2021-06-28
View on DB Fiddle
Schema (MySQL v8.0)
CREATE TABLE Diseaselogs (
`id` INTEGER,
`logType` VARCHAR(8),
`userId` INTEGER,
`date` VARCHAR(10)
);
INSERT INTO Diseaselogs
(`id`, `logType`, `userId`, `date`)
VALUES
('1', 'positive', '1', '2021-06-21'),
('2', 'negative', '2', '2021-06-22'),
('3', 'pending', '1', '2021-06-24'),
('4', 'negative', '1', '2021-06-26'),
('5', 'negative', '2', '2021-06-21'),
('6', 'pending', '3', '2021-06-23'),
('7', 'negative', '1', '2021-06-24'),
('8', 'negative', '2', '2021-06-25'),
('9', 'pending', '3', '2021-06-28');
CREATE TABLE users (
`id` INTEGER,
`name` VARCHAR(4),
`age` INTEGER
);
INSERT INTO users
(`id`, `name`, `age`)
VALUES
('1', 'Nam', '21'),
('2', 'Thao', '23'),
('3', 'An', '19');
Query #1
SELECT
u.id, `name`, `age`,`logType`, `date`
FROM
(SELECT
`logType`, `userId`, `date`
, ROW_NUMBER() OVER (PARTITION BY `userId` ORDER BY `date` DESC) rn
FROM
Diseaselogs) t1
INNER JOIN users u ON t1.userId = u.id
WHERE rn = 1;
id
name
age
logType
date
1
Nam
21
negative
2021-06-26
2
Thao
23
negative
2021-06-25
3
An
19
pending
2021-06-28
View on DB Fiddle

how to search data in mysql using like operator on date time column

I am creating MySQL query where I need to find data from created_by column (having datetime datatype) using like operator.
I have developed following query:
SELECT `order_id`,`order_no`,`name`,`email`,`created_at` FROM orders WHERE
DATE_FORMAT(created_at,'%Y-%m-%d %H:%i')=DATE_FORMAT('2021-02-23 17:37:28','%Y-%m-%d %H:%i')
but I want to search data with like operator
for example
if I pass created_at date like '2021-02' then it should give me all the result related to this.
if I pass created_at date like '2021-02-23 17:' then it should give me all the result related to this.
if I pass created_at date like '2021-' then it should give me all the result related to this.
if I pass created_at date like '2021-' then it should give me all the result related to this.
and so many combination like that.
I have tried this query and it returning expected result
*SELECT `order_id`,`order_no`,`name`,`email`,`created_at` FROM orders WHERE
created_at LIKE '2021-02-23 17:37:28'*
output:
but if I tried this query I unable to get expected result it returning 0 rows
SELECT `order_id`,`order_no`,`name`,`email`,`created_at` FROM orders WHERE
created_at LIKE '2021-02-23 17:37:'
output:
please find bellow table script to regenerate issue.
(you can put any available date from provided data in created_by column)
create table `orders` (
`order_id` int (11),
`order_no` varchar (300),
`sub_order_no` varchar (300),
`name` varchar (300),
`email` varchar (300),
`created_at` datetime
);
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_by`) values('1','202102','964','23038','pqr#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_by`) values('2','202102','965','22166638','abc#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_by`) values('3','202133','966','2202166638','def#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_by`) values('4','202044','967','2302166638','jkl#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_by`) values('5','202105','968','2302166638','lmn#gmail.com','2021-02-23 17:37:28');
as my knowledge in MySQL is limited so guys your help will be apricated to improve myself, thank you !!
Mysql recognizes dates, if you write the correct format
So you can use a simple =
LIKE is only for strings
You have a lot if [functions][1] for date and time, i am sure yyou find the correct to get your orders
create table `orders` (
`order_id` int (11),
`order_no` varchar (300),
`sub_order_no` varchar (300),
`name` varchar (300),
`email` varchar (300),
`created_at` datetime
);
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_at`) values('1','202102','964','23038','pqr#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_at`) values('2','202102','965','22166638','abc#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_at`) values('3','202133','966','2202166638','def#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_at`) values('4','202044','967','2302166638','jkl#gmail.com','2021-02-23 17:37:28');
insert into `orders` (`order_id`, `order_no`, `sub_order_no`, `name`, `email`, `created_at`) values('5','202105','968','2302166638','lmn#gmail.com','2021-02-23 17:37:28');
SELECT `order_id`,`order_no`,`name`,`email`,`created_at` FROM orders WHERE
created_at ='2021-02-23 17:37:28'
order_id | order_no | name | email | created_at
-------: | :------- | :--------- | :------------ | :------------------
1 | 202102 | 23038 | pqr#gmail.com | 2021-02-23 17:37:28
2 | 202102 | 22166638 | abc#gmail.com | 2021-02-23 17:37:28
3 | 202133 | 2202166638 | def#gmail.com | 2021-02-23 17:37:28
4 | 202044 | 2302166638 | jkl#gmail.com | 2021-02-23 17:37:28
5 | 202105 | 2302166638 | lmn#gmail.com | 2021-02-23 17:37:28
SELECT `order_id`,`order_no`,`name`,`email`,`created_at` FROM orders WHERE
DATE_FORMAT(created_at,'%Y-%m') ='2021-02'
order_id | order_no | name | email | created_at
-------: | :------- | :--------- | :------------ | :------------------
1 | 202102 | 23038 | pqr#gmail.com | 2021-02-23 17:37:28
2 | 202102 | 22166638 | abc#gmail.com | 2021-02-23 17:37:28
3 | 202133 | 2202166638 | def#gmail.com | 2021-02-23 17:37:28
4 | 202044 | 2302166638 | jkl#gmail.com | 2021-02-23 17:37:28
5 | 202105 | 2302166638 | lmn#gmail.com | 2021-02-23 17:37:28
db<>fiddle here

Double GroupBy with Count and Dates Returns Wrong Dates

I have three tables to keep track of emails and their assigned categories: Email keeps the mail's content, Category lists the categories and Classification links an Email entry ID with a Category entry ID. Schema with sample data and query is available on SQLFiddle: http://sqlfiddle.com/#!9/a410a6/26/0
CREATE TABLE `Category` (
`id` int(6) unsigned NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Mail` (
`id` int(6) unsigned NOT NULL,
`content` varchar(500) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Classification` (
`id` int(6) unsigned NOT NULL,
`mail_id` int(6) unsigned NOT NULL,
`category_id` int(6) unsigned NOT NULL,
FOREIGN KEY (mail_id) REFERENCES Mail(id),
FOREIGN KEY (category_id) REFERENCES Category(id),
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `Category` (`id`, `name`) VALUES
('1', 'Important'),
('2', 'Urgent'),
('3', 'Normal');
INSERT INTO `Mail` (`id`, `content`, `date`) VALUES
('1', 'Important Email', '2019-01-04T13:53:52'),
('2', 'Urgent Email', '2019-01-19T13:53:52'),
('3', 'Very Urgent Email', '2019-01-24T13:53:52'),
('4', 'Quite Urgent Email', '2019-01-24T13:53:52'),
('5', 'Normal Email', '2019-01-21T13:53:52'),
('6', 'Regular Email', '2019-01-14T13:53:52'),
('7', 'Regular Email', '2019-01-23T13:53:52'),
('8', 'Regular Email', '2019-01-23T13:53:52'),
('9', 'Regular Email', '2019-01-20T13:53:52'),
('10', 'Very Urgent Email', '2019-01-25T13:53:52'),
('11', 'Very Urgent Email', '2019-01-25T13:53:52');
INSERT INTO `Classification` (`id`, `mail_id`, `category_id`) VALUES
('1', '1', '1'),
('2', '2', '2'),
('3', '3', '2'),
('4', '4', '2'),
('5', '5', '3'),
('6', '6', '3'),
('7', '6', '3'),
('8', '6', '3'),
('9', '6', '3'),
('10', '6', '2'),
('11', '6', '2');
I want to return the number of mails received for each category for each date recorded, i.e. my expected results would be
+----------------------+-----------+----------+
| date | name | count(*) |
+----------------------+-----------+----------+
| 2019-01-04T13:53:52Z | Important | 1 |
| 2019-01-14T13:53:52Z | Normal | 1 |
| 2019-01-19T13:53:52Z | Urgent | 1 |
| 2019-01-20T13:53:52Z | Normal | 1 |
| 2019-01-21T13:53:52Z | Normal | 1 |
| 2019-01-23T13:53:52Z | Normal | 2 |
| 2019-01-24T13:53:52Z | Urgent | 1 |
| 2019-01-25T13:53:52Z | Urgent | 2 |
+----------------------+-----------+----------+
To do so I run the following query with a double groupby, filtering on the Classification table:
SELECT Mail.date, Category.name, count(*) FROM Mail, Classification, Category WHERE Category.id = Classification.category_id AND Classification.mail_id = Mail.id GROUP BY Mail.date, Category.name
Which gives me the following results:
+----------------------+-----------+----------+
| date | name | count(*) |
+----------------------+-----------+----------+
| 2019-01-04T13:53:52Z | Important | 1 |
| 2019-01-14T13:53:52Z | Normal | 4 |
| 2019-01-14T13:53:52Z | Urgent | 2 |
| 2019-01-19T13:53:52Z | Urgent | 1 |
| 2019-01-21T13:53:52Z | Normal | 1 |
| 2019-01-24T13:53:52Z | Urgent | 2 |
+----------------------+-----------+----------+
Which is entirely wrong.
I've tried substituting the WHERE statement for a JOIN:
SELECT Mail.date, Category.name, count(*) FROM (Mail, Category) RIGHT JOIN Classification ON Category.id = Classification.category_id AND Classification.mail_id = Mail.id GROUP BY Mail.date, Category.name `
But I get the exact same results as above.
Why are those queries returning these erroneous results and what should I do to fix them ?
First, your query should look like this:
SELECT m.date, c.name, count(*)
FROM Mail m JOIN
Classification cl
ON cl.mail_id = m.id JOIN
Category c
ON c.id = cl.category_id
GROUP BY m.date, c.name ;
Now that we have gotten that out of the way, your problem is that emails have multiple categories. So, they are multiply counted. Hence, the results you are getting are correct.
You have exact duplicates in the classification table, so a simple solution is:
SELECT m.date, c.name, count(distinct m.id)
FROM Mail m JOIN
Classification cl
ON cl.mail_id = m.id JOIN
Category c
ON c.id = cl.category_id
GROUP BY m.date, c.name ;
That said, the real solution is to fix your data, so it doesn't have duplicates.
Here is the SQL Fiddle using your data. You have a "2" for emails on 2019-01-23. However, there are no classified emails on that date, so they are not in the results.

MySQL Left join with grouping and date

As you can see on this sqlfiddle, I have this schema:
CREATE TABLE reviews
(`id` int(11) NOT NULL AUTO_INCREMENT,
`shop_id` int(11),
`order_id` char(255),
`product_id` char(32),
`review_time` int(11),
PRIMARY KEY (`id`)
)
;
INSERT INTO reviews
(`shop_id`, `order_id`, `product_id`, `review_time`)
VALUES
('10', '100', '1000', '1466190000'),
('10', '100', '1000', '1466276400'),
('10', '100', '1000', '1466462800'),
('20', '800', '8000', '1466249200')
;
CREATE TABLE tags
(`id` int(11) NOT NULL AUTO_INCREMENT,
`shop_id` int(11),
`order_id` char(255),
`product_id` char(32),
`tag_time` INT(11) NULL,
PRIMARY KEY (`id`)
)
;
INSERT INTO tags
(`shop_id`, `order_id`, `product_id`, `tag_time`)
VALUES
('10', '100', '1000', '1466449200'),
('10', '100', '1000', NULL),
('10', '100', '3000', NULL),
('20', '800', '8000', '1469449200')
;
I need to get statistics by date showing how many reviews I have per date and how many were tagged and how many were not. I'm using this query:
SELECT
DATE_FORMAT(FROM_UNIXTIME(r.`review_time`), "%d.%m.%Y") AS review_submited_on,
r.`shop_id`,
COUNT(*) as total_orders,
COUNT(*) as tagged_orders
FROM
reviews AS r
LEFT JOIN tags as t
ON r.`shop_id` = t.`shop_id` AND
r.`order_id` = t.`order_id` AND
r.`product_id` = t.`product_id`
WHERE
t.`tag_time` IS NOT NULL
GROUP BY r.`shop_id`, r.`order_id`, r.`product_id`
ORDER BY review_submited_on ASC
UPDATE
The expected result would look like this:
| review_submited_on | shop_id | total_orders | tagged_orders |
|--------------------|---------|--------------|---------------|
| 17.06.2016 | 10 | 3 | 1 |
| 18.06.2016 | 20 | 1 | 1 |
I created this sqlfiddle for demo.
Thanks for any help :)
Try this, and let me know if that is something you want.
SELECT review_submited_on, shop_id, total_orders, IFNULL(tagged_orders, 0) tagged_orders
FROM
(SELECT shop_id, COUNT(DISTINCT shop_id, order_id, product_id) total_orders, DATE_FORMAT(FROM_UNIXTIME(review_time), "%d.%m.%Y") AS review_submited_on
FROM reviews
GROUP BY shop_id) review_counter
LEFT JOIN
(SELECT shop_id, COUNT(DISTINCT shop_id, order_id, product_id) tagged_orders
FROM tags
WHERE tag_time IS NOT NULL
GROUP BY shop_id) tag_counter
USING (shop_id)
Result
| review_submited_on | shop_id | total_orders | tagged_orders |
|--------------------|---------|--------------|---------------|
| 17.06.2016 | 10 | 1 | 1 |
| 18.06.2016 | 20 | 1 | 1 |

how I get the preview product and next product in mysql?

how I get the preview product and next product in mysql?
for example: the current product is id 7 , I want to get 5 and 8 in table p , how to write the sql?
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `p`
-- ----------------------------
DROP TABLE IF EXISTS `p`;
CREATE TABLE `p` (
`id` int(10) NOT NULL auto_increment,
`products_name` varchar(200) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of p
-- ----------------------------
INSERT INTO `p` VALUES ('1', 'a');
INSERT INTO `p` VALUES ('2', 'b');
INSERT INTO `p` VALUES ('4', 'd');
INSERT INTO `p` VALUES ('5', 'ed');
INSERT INTO `p` VALUES ('11', 'f');
INSERT INTO `p` VALUES ('7', 'gs');
INSERT INTO `p` VALUES ('8', 'd');
INSERT INTO `p` VALUES ('9', 'f');
SELECT P1.id,
P1.Products_Name
FROM P P1
INNER JOIN
(SELECT max(id)as ID FROM P WHERE id < 7
UNION ALL
SELECT min(id)as ID FROM P WHERE id > 7
)T ON T.ID = P1.ID
ORDER BY P1.ID ASC
sqlFiddle example here
you could accomplish that using HANDLER, but this is not standard. BTW, what you want is difficult with only Standard SQL.
mysql> HANDLER p OPEN;
Query OK, 0 rows affected (0.00 sec)
mysql> HANDLER p READ `PRIMARY` = (7);
+----+---------------+
| id | products_name |
+----+---------------+
| 7 | gs |
+----+---------------+
1 row in set (0.00 sec)
mysql> HANDLER p READ `PRIMARY` NEXT;
+----+---------------+
| id | products_name |
+----+---------------+
| 8 | d |
+----+---------------+
1 row in set (0.00 sec)
mysql> HANDLER p READ `PRIMARY` PREV LIMIT 1,1;
+----+---------------+
| id | products_name |
+----+---------------+
| 5 | ed |
+----+---------------+