mysql, query how to goup same value and count that value - mysql

i have data table like that :
month IKU value
2 1b 1
2 1b 1
1 2a 1
1 1a 1
the results I want like that :
month IKU value
2 1b 2
1 1a,2a 1,1
is that possible?

You need to use GROUP BY twice along with GROUP_CONCAT function like below:
SELECT
tmp.month,
GROUP_CONCAT(tmp.IKU) AS IKU,
GROUP_CONCAT(tmp.summedValue) AS value
FROM
(
SELECT
month,
IKU,
SUM(value) AS summedValue
FROM t
GROUP BY month,IKU
) AS tmp
GROUP BY tmp.month
ORDER BY tmp.month DESC
GROUP_CONCAT() function
MySQL GROUP_CONCAT() function returns a string with concatenated non-NULL value from a group.
Returns NULL when there are no non-NULL values.
Test:
-- ----------------------------
-- Table structure for `t`
-- ----------------------------
DROP TABLE IF EXISTS `t`;
CREATE TABLE `t` (
`month` int(11) DEFAULT NULL,
`IKU` varchar(10) DEFAULT NULL,
`value` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of t
-- ----------------------------
INSERT INTO `t` VALUES ('2', '1b', '1');
INSERT INTO `t` VALUES ('2', '1b', '1');
INSERT INTO `t` VALUES ('1', '2a', '1');
INSERT INTO `t` VALUES ('1', '1a', '1');

Try this. Didn't get chance to test it as MySQL fiddle isn't working, but the idea is to first sum(value) for each combination of month,iku. Then use group_concat to concatenate the resultset.
select month
,group_concat(IKU separator ',')
,group_concat(value separator ',')
from
(select month,IKU,sum(value) as value
from Table1 group by month,IKU
) t
group by IKU

Related

Sum qty but result is weird in Mysql

I'm using MySQL query to sum qty, but the result a little bit weird, this is my query"
SELECT SUM(qty) FROM inventory_logs
WHERE product_id =12 AND `type` = 'is' AND deleted_at IS null
The data I want to sum:
The result:
4.440892098500626e-16
For additional info, the data type qty column is VARCHAR.
So as I mentioned in my comment, you will need to CAST your varchar values into decimal values and then sum them.
This should do the trick:
SELECT
FORMAT(CAST(SUM(qty) AS DECIMAL(12,2)),2) AS qty_sum
FROM
inventory_logs
WHERE
product_id =12 AND `type` = 'is' AND deleted_at IS null
Test fiddle here.
Use this simple trick to make a number of it, but because of the fractal you need also to use a Round for
SELECT ROUND(SUM(qty + 0),2) FROM inventory_logs
WHERE product_id =12 AND `type` = 'is' AND deleted_at IS null
Schema (MySQL v5.7)
CREATE TABLE inventory_logs (
qty VARCHAR(5)
);
INSERT INTO inventory_logs(qty) VALUES('0');
INSERT INTO inventory_logs(qty) VALUES('2.74');
INSERT INTO inventory_logs(qty) VALUES('1.07');
INSERT INTO inventory_logs(qty) VALUES('-3.81');
INSERT INTO inventory_logs(qty) VALUES('3.81');
INSERT INTO inventory_logs(qty) VALUES('-3.81');
Query #1
SELECT ROUND(SUM(qty + 0),2) FROM inventory_logs;
| ROUND(SUM(qty + 0),2) |
| --------------------- |
| 0 |
View on DB Fiddle
Add a 0 to the SUM function it should work:
SELECT SUM(qty + 0) FROM inventory_logs
WHERE product_id =12 AND `type` = 'is' AND deleted_at IS null

Combine temporary table of dates with two tables and fill in missing values?

I have a rates table which holds rows of nightly rates per day. I have a ratecodes table which houses different ratecodes mapped to rates.
My goal is to find any missing rates for any days for an X period of time. For this example let's use 1 month.
Desired result: 64 rows of which 2 rows are filled with information with the first rate code. The second rate code has absolutely no rows in rates but I need to show that it's actually missing dates. ( 64 because 1 month from now returns 32 days x 2 rate codes )
Two tables in question:
CREATE TABLE `ratecode` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ratecode` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `ratecode` VALUES ('1', 'BLAH');
INSERT INTO `ratecode` VALUES ('2', 'NAH');
CREATE TABLE `rates` (
`thedate` date DEFAULT NULL,
`rate` double DEFAULT NULL,
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ratecode` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `rates` VALUES ('2014-12-27', '999', '1', '1');
INSERT INTO `rates` VALUES ('2014-12-26', '99', '2', '1');
So using this query, in 2 parts. Part 1 is a temporary table of dates from today to 1 month ahead:
CREATE TEMPORARY TABLE IF NOT EXISTS `myDates` AS (
SELECT
CAST((SYSDATE()+INTERVAL (H+T+U) DAY) AS date) d
FROM ( SELECT 0 H
UNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300
) H CROSS JOIN ( SELECT 0 T
UNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30
UNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60
UNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90
) T CROSS JOIN ( SELECT 0 U
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) U
WHERE
(SYSDATE()+INTERVAL (H+T+U) DAY) <= (SYSDATE()+INTERVAL 1 MONTH)
ORDER BY d ASC
);
And part 2 is the actual selection going on:
SELECT
*
FROM
rates
RIGHT JOIN myDates ON ( myDates.d = rates.thedate )
LEFT OUTER JOIN ratecode ON ( rates.ratecode = ratecode.id )
This returns only 32 rows back because in rates, there are 2 records for the first entry in ratecode. I don't get back the 32 missing rows for the other ratecode. How can I adjust in order to retain this information?
After I get the 64 rows back, I also need to filter for which ones are "blank" or haven't been entered in rates. So missing values only.
If I understand correctly, you want to generate all the rows using a cross join, then left join to the data and filter out all th ematches:
select rc.ratecode, d.d as missingdate
from ratecode rc cross join
mydates d left join
rates r
on rc.id = r.ratecode and d.d = r.thedate
where r.id is null;

MySQL - Select multiple values across multiple columns where all matches have a result

I am trying to construct a query that will allow me to "filter" on pairs of columns for particular criteria. I need to be able to construct multiple filters for the same given pair. The end result should only return instances that have data for the case where all filters are applied.
I constructed a trivial example demonstrating what I would like to be able to do.
Using the follow table definition:
DROP TABLE IF EXISTS foo;
CREATE TEMPORARY TABLE `foo` (
`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`Index` INT UNSIGNED NOT NULL,
`Header` VARCHAR(50) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE INDEX `ID_UNIQUE` (`ID` ASC));
INSERT INTO `foo` (`Index`, `Header`, `Value`)
VALUES
(0, 'Header_1', 'a'),
(0, 'Header_2', 'b'),
(1, 'Header_1', 'a'),
(1, 'Header_2', 'c');
I would like a query that would return the following, given that you are looking for the case where 'Header_1' == 'a' and 'header_2' == 'b':
Index | Header | Value
------------------------
0 | Header_1 | a
0 | Header_2 | b
My current attempt is as follows:
SELECT `Index`, `Header`, `Value` FROM `foo`
WHERE (
(`Header` = 'Header_1') AND (`Value` = 'a')
OR (
(`Header` = 'Header_2') AND (`Value` = 'b')
)
)
GROUP BY `Header`, `Value`
HAVING COUNT(DISTINCT `Index`) = 2
ORDER BY `Index`, `Header`;
That code returns the following:
Index | Header | Value
------------------------
0 | Header_1 | a
I am missing one of my return rows. How can I restructure the query to return all of the matching rows?
Note that I declared the table as a temporary table. This is important, as I am working with temporary tables, and they have special restrictions to keep in mind (namely not being able to open it more than once in the same statement).
Your query returns only header_1 because the clause:
HAVING COUNT(DISTINCT `Index`) = 2
is only correct for Header_1.
Header_2 has count=1, therefore removed from the end result.
To get a clearer picture of what i say use:
SELECT `Index`, `Header`, `Value`, COUNT(DISTINCT `Index`) FROM `foo`
WHERE (
(`Header` = 'Header_1') AND (`Value` = 'a')
OR (
(`Header` = 'Header_2') AND (`Value` = 'b')
)
)
GROUP BY `Header`, `Value`
ORDER BY `Index`, `Header`;
and take a look at the last column.
I couldn't figure out how to do this with only the one temporary table. I'm not happy with this result, but at least it works.
DROP TABLE IF EXISTS `foo2`;
CREATE TEMPORARY TABLE `foo2` (
SELECT `Index` FROM `foo`
WHERE (
(`Header` = 'Header_1') AND (`Value` = 'a')
OR (
(`Header` = 'Header_2') AND (`Value` = 'b')
)
)
GROUP BY `Index`
HAVING COUNT(DISTINCT `Header`) = 2
);
SELECT DISTINCT t1.`Index`, t1.`Header`, t1.`Value` FROM `foo` t1
INNER JOIN `foo2` t2 ON t2.`Index` = t1.`Index`
ORDER BY t1.`Index`, t1.`Header`;
How about...
SELECT `index`
FROM foo
WHERE (header,value) IN (('header_1','a'))
OR (header,value) IN (('header_2','b'))
GROUP
BY `index`
HAVING COUNT(*) = 2;

MySQL multiple COUNTs

I have a table like this:
Fiddle: http://sqlfiddle.com/#!2/44d9e/14
CREATE TABLE IF NOT EXISTS `mytable` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(20) NOT NULL,
`money_earned` int(20) NOT NULL,
PRIMARY KEY (`id`)
) ;
INSERT INTO mytable (user_id,money_earned) VALUES ("111","10");
INSERT INTO mytable (user_id,money_earned) VALUES ("111","6");
INSERT INTO mytable (user_id,money_earned) VALUES ("111","40");
INSERT INTO mytable (user_id,money_earned) VALUES ("222","45");
INSERT INTO mytable (user_id,money_earned) VALUES ("222","1");
INSERT INTO mytable (user_id,money_earned) VALUES ("333","5");
INSERT INTO mytable (user_id,money_earned) VALUES ("333","19");
I need to know table has how many rows, how many different users, and how many times each user has earned.
I need this result:
TOTAL_ROWS: 7
TOTAL_INDIVIDUAL_USERS: 3
USER_ID USER_TIMES
111 3
222 2
333 2
Is your problem that you want the total as well? If so, then you can get this using rollup:
SELECT coalesce(cast(user_id as char(20)), 'TOTAL USER_TIMES'),
COUNT(*) as times
FROM mytable
GROUP BY user_id with rollup;
You can get the user counts in a separate column with this trick:
SELECT coalesce(cast(user_id as char(20)), 'TOTAL USER_TIMES'),
COUNT(*) as times, count(distinct user_id) as UserCount
FROM mytable
GROUP BY user_id with rollup;
You realize that a SQL query just returns a table of values. You are asking for very specific formatting, which is typically done better at the application level. That said, you can get close to what you want with something like this:
select user, times
from ((SELECT 3 as ord, cast(user_id as char(20)) as user, COUNT(*) as times
FROM mytable
GROUP BY user_id
)
union all
(select 1, 'Total User Count', count(*)
from mytable
)
union all
(select 2, 'Total Users', count(distinct user_id)
from mytable
)
) t
order by ord;
I think this could be a typo anyway your are trying to sum your COUNT() times, simply replace with money_earned
SELECT user_id,
COUNT(*) AS 'times',
SUM(money_earned) AS 'sum_money'
FROM mytable GROUP BY user_id;
SQL Fiddle

How to combine sql request with data in another table

I have two tables, first "users_counts"
id int(11) AUTO_INCREMENT
name varchar(250)
And I have second table "counts_data"
id int(11) AUTO_INCREMENT
id_user int(11)
count int(11)
date datetime
I want to select all records from the first table and get some data from a second, and then I want to merge they. I want create temp (for one request) column where collect last count with order by date in second table and second column where collect collect penultimate count with order by date in second table.
INSERT INTO `users_counts` (`id`,`name`) VALUES ('1','John');
INSERT INTO `users_counts` (`id`,`name`) VALUES ('2','Michael');
INSERT INTO `users_counts` (`id`,`name`) VALUES ('3','Den');
INSERT INTO `counts_data` (`id`,`id_user`, `count`, `date`) VALUES ('1','1', '200', '2012.09.09');
INSERT INTO `counts_data` (`id`,`id_user`, `count`, `date`) VALUES ('2','1', '212', '2012.09.01');
INSERT INTO `counts_data` (`id`,`id_user`, `count`, `date`) VALUES ('3','2', '20', '2012.01.09');
INSERT INTO `counts_data` (`id`,`id_user`, `count`, `date`) VALUES ('4','3', '210', '2012.02.09');
INSERT INTO `counts_data` (`id`,`id_user`, `count`, `date`) VALUES ('5','3', '2033', '2012.03.09');
INSERT INTO `counts_data` (`id`,`id_user`, `count`, `date`) VALUES ('6','3', '1', '2012.04.09');
In the end, after a request I want to get something like this
id name count count_before
1 John 200 212
2 Michael 20 0
3 Den 1 2033
Thank.
Another possible way to do this:
select uc.id,
uc.name,
(select count
from counts_data cd
where cd.id_user = uc.id
order by date desc limit 1) as count,
ifnull((select count
from counts_data cd
where cd.id_user = uc.id
order by date desc limit 1 offset 1),0) as count_before
from users_counts uc;
Since you only need one value from the counts_data for each row/record, you can use in-line queries in mySQL
SQL Fiddle
select uc.id
, uc.name
, cd1.count
, cd3.count as count_before
from users_counts uc
left join
counts_data cd1
on cd1.id_user = uc.id
and cd.date =
(
select max(date)
from counts_data cd2
where cd2.id_user = uc.id_user
)
left join
counts_data cd3
on cd3.id_user = uc.id
and cd.date =
(
select max(date)
from counts_data cd4
where cd4.id_user = uc.id_user
and cd4.date <> cd1.date
)