How to compute column by specific value? - mysql

How to query result like these picture.
First column select is this month plus next column by condition field (SelectColumn)
yellow background is the select column for sum
my example code.
declare #myDate date = getdate(),#qry varchar(max)
set #qry = 'select case v.SelectColumn
when 0 then (SELECT '+DATENAME(month,#myDate)+')
when 2 then (SELECT '+DATENAME(month,#myDate)+'+'+DATENAME(MONTH,DATEADD(MONTH,1,#myDate))+')
when 1 then (SELECT '+DATENAME(month,#myDate)+'+'+DATENAME(MONTH,DATEADD(MONTH,1,#myDate))+'+'+DATENAME(MONTH,DATEADD(MONTH,2,#myDate))+')
end
as SumColumn
from vwQC12Month v'
exec (#qry)

This problem requires the monthly values to be accessible as rows such that selected aggregation can be applied. Typically, you can use UNPIVOT or VALUES to rotate columns into rows. Below is a working example using UNPIVOT.
In the query below, you'd have to change the short form month names to match your column names for it to work. Here is a working demo of this: http://sqlfiddle.com/#!18/094e4/2
Also you might want to consider how you want to deal with year end wrapping and adjust the aggregation accordingly.
-- setup sample data
create table Test (
id int, Jan int, Feb int, Mar int, Apr int, May int,
Jun int, Jul int, Aug int, Sep int, Oct int, Nov int, Dec int,
SelectColumn int)
insert Test values
(1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 1),
(2, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 2),
(3, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 3),
(4, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 4)
-- query
DECLARE #currentMonthNumber int = MONTH(getdate())
-- CTE that rotates the data into rows
; WITH RowsByMonth(id, SelectColumn, monthNumber, val) AS
(
SELECT id, SelectColumn, CONVERT(int, month) AS monthNumber, val
FROM
(SELECT id, SelectColumn,
Jan AS [1], Feb AS [2], Mar AS [3], Apr AS [4],
May AS [5], Jun AS [6], Jul AS [7], Aug AS [8],
Sep AS [9], Oct AS [10], Nov AS [11], Dec AS [12]
FROM Test) AS Source
UNPIVOT
(val FOR month IN
([1], [2], [3], [4],
[5], [6], [7], [8],
[9], [10], [11], [12])
) AS asRows
) -- aggregation below
SELECT id, SUM(val) AS SumAcrossSelectedMonths
FROM RowsByMonth
WHERE
monthNumber >= #currentMonthNumber
AND monthNumber - #currentMonthNumber < SelectColumn
GROUP BY id
-- Results
| id | SumAcrossSelectedMonths |
|----|-------------------------|
| 1 | 40 |
| 2 | 90 |
| 3 | 150 |
| 4 | 220 |

Related

Finding Connection Pairs

Suppose we have a table in mySQL database where fname has a connection to another fname(BB_Connection_name), we would like have a query to find the pair(s) of friends who find connection among themselves.
E.g
Sidharth and Asim both have each others BBid and BB_Connection_ID
I have looked for similar case of father, son and grandson question but in that not each father has a son and thus inner joining them makes things easier for solving. I tried using that but didn't work.
Here i need to check BB_Connection_ID for every fname(A) and then corresponding fname has A's BBid as his BB_Connection_ID or not.
The pairs which would be chosen, should be like Sidharth<->Asim
We need to find the pairs who have their connection ID to each other.
==========================================================================
Code for recreation of the table:
-----------------------------------------------------------------------------
create table world.bigbb(
BBid int not null auto_increment,
fname varchar(20) NOT NULL,
lname varchar(30),
BBdays int not null,
No_of_Nom int,
BB_rank int not null,
BB_Task varchar(10),
BB_Connection_ID int,
BB_Connection_name varchar(10),
primary key (BBid)
);
insert into world.bigbb (fname, lname, BBdays, No_of_Nom, BB_rank, BB_Task, BB_Connection_ID, BB_Connection_name)
values
('Sidharth', 'Shukla', 40, 4, 2, 'Kitchen', 11, 'Asim'),
('Arhaan', 'Khan', 7, 1, 9, 'Kitchen', 16, 'Rashmi'),
('Vikas', 'Bhau', 7, 1, 8, 'Bedroom', 11, 'Asim'),
('Khesari', 'Bihari', 7, 1, 12, 'Kitchen', 9, 'Paras'),
('Tehseem', 'Poonawala', 7, 1, 11, 'Washroom', 12, 'Khesari'),
('Shehnaaz', 'Gill', 40, 4, 4, 'Washroom', 9, 'Paras'),
('Himanshi', 'Khurana', 7, 0, 7, 'Bedroom', 8, 'Shefali'),
('Shefali', 'Zariwala', 7, 1, 10, 'Bedroom', 1, 'Sidharth'),
('Paras', 'Chabra', 40, 3, 1, 'Bathroom', 10, 'Mahira'),
('Mahira', 'Sharma', 40, 4, 5, 'Kitchen', 9, 'Paras'),
('Asim', 'Khan', 40, 3, 3, 'Bathroom', 1, 'Sidharth'),
('Arti', 'Singh', 40, 5, 6, 'Captain', 1, 'Sidharth'),
('Sidharth', 'Dey', 35, 6, 16, 'None', 14, 'Shefali'),
('Shefali', 'Bagga', 38, 5, 15, 'None', 13, 'Sidharth'),
('Abu', 'Fifi', 22, 5, 17, 'None', 11, 'Asim'),
('Rashmi', 'Desai', 38, 5, 13, 'None', 17, 'Debolina'),
('Debolina', 'Bhattacharjee', 38, 5, 14, 'None', 16, 'Rashmi');
One solution would be to self-join the table:
select
b1.fname name1,
b2.fname name2
from bigbb b1
inner join bigbb b2
on b1.BB_Connection_ID = b2.BBid
and b2.BB_Connection_ID = b1.BBid
and b1.BBid < b2.BBid
This will give you one record for each pair, with the record having the smallest BBid in the first column.
This demo on DB Fiddle with your sample data returns:
name1 | name2
:------- | :-------
Sidharth | Asim
Paras | Mahira
Sidharth | Shefali
Rashmi | Debolina

With couchbase, how to sum total by day

I am looking to total (sum) equipment used by day. The data i have is {job, toDate, fromDate, equipmentUsed}. Would mapreduce be the best and how would i do that with the "to" and "from" dates?
Here is some background. We have many projects. Many workorders for each projects. Workorders are by day and have inventory for that day. i want to sum the inventory for each day in a date range to see if we will run out of inventory.
I will post sample data shortly
{“project::100”: {“name”: “project one”}
,“project::101”: {“name”: “project two”}
,”workOrder::1000”: {“project”: “project::100”, “dateNeeded”: jan 1, “inventory”: [“equip1”: 2, “equip2”: 1, “equip3”: 3 , “equip4”: 4]}
,”workOrder::1001”: {“project”: “project::100”, “dateNeeded”: jan 2, “inventory”: [“equip1”: 1 , “equip2”: 2 , “equip3”: 1 , “equip4”: 4]}
,”workOrder::1002”: {“project”: “project::100”, “dateNeeded”: jan 4, “inventory”: [“equip1”: 1, “equip2”: 2, “equip3”: 3, “equip4”: 1 ]}
,”workOrder::1000”: {“project”: “project::101”, “dateNeeded”: jan 1, “inventory”: [“equip1”: 1, “equip2”: 3, “equip4”: 1]}
,”workOrder::1001”: {“project”: “project::101”, “dateNeeded”: jan 3, “inventory”: [ “equip2”: 1, “equip3”: 3 , “equip4”: 1]}
,”workOrder::1002”: {“project”: “project::101”, “dateNeeded”: jan 4, “inventory”: [“equip1”: 1, “equip2”: 1, “equip3”: 2 , “equip4”: 3]}
}
Can you give an example of what exactly you want? Looks like you want to consider aggregating equipUsed for the overlapping dates, as well as gaps in the date ranges etc. For ex:
{J1, Jan 7, Jan 1, 4},
{J2, Jan 4, Jan 2, 7},
{J3, Jan 10, Jan 5, 10},
{J4, Jan 25, Jan 15, 20} etc.,
The output is:
{Jan 1, 4}, {Jan2, 11 /4 + 7/}, {Jan 3, 11}, {Jan4, 11}, {jan 5, 14 /4+10/}, {Jan 6, 14}, {Jan 7, 14}, {Jan 8, 10}, {Jan 9, 10}, {Jan 10, 10}, {Jan 11 to 14th, 0}, and {Jan 15th to 25th, 20} etc.,
This is some non-trivial logic. You can use N1QL API with some programming language (java, python, node etc) to solve this. For example, an exhaustive algorithm in pseudo code is (assuming docs in 'default' bucket):
minDate = Run_N1QLQuery("SELECT MIN(fromDate} from default");
maxDate = Run_N1QLQuery("SELECT MAX(toDate) from default");
for d = minDate to maxDate
sum_used = Run_N1QLQuery("SELECT SUM(equipUsed) from default WHERE %s BETWEEN fromDate AND toDate", d);
d = increment_date(d);
Depending on what is exactly needed, one can write much more efficient algorithm.
hth,
-Prasad

SQL: value higher than percentage of population of values

I wish to calculate the value which is higher than a percentage of the population of values, this per group.
Suppose I have:
CREATE TABLE project
(
id int,
event int,
val int
);
INSERT INTO project(id,event,val)
VALUES
(1, 11, 43),
(1, 12, 19),
(1, 13, 19),
(1, 14, 53),
(1, 15, 45),
(1, 16, 35),
(2, 21, 22),
(2, 22, 30),
(2, 23, 25),
(2, 24, 28);
I now want to calculate for each id what is the val that will be for example higher than 5%, or 30% of the val for that id.
For example, for id=1, we have the following values: 43, 19, 19, 53, 45, 35.
So the contingency table would look like this:
19 35 43 45 53
2 1 1 1 1
and the val=20 (higher than 19) would be chosen to be higher than 5% (actuall 2 out of 6) of the rows.
The contengency table for id 2 is:
22 25 28 30
1 1 1 1
My expected out is:
id val_5p_coverage val_50p_coverage
1 20 36
2 23 26
val_5p_coverage is the value val needed to be above at least 5% of val in the id.
val_50p_coverage is the value val needed to be above at least 50% of val in the id.
How can I calculate this with SQL ?
I managed to do it in HiveQL (for Hadoop) as follows:
create table prep as
select *,
CUME_DIST() OVER(PARTITION BY id ORDER BY val ASC) as proportion_val_equal_or_lower
from project
SELECT id,
MIN(IF(proportion_val_equal_or_lower>=0.05, val, NULL)) AS val_5p_coverage,
MIN(IF(proportion_val_equal_or_lower>=0.50, val, NULL)) AS val_50p_coverage
FROM prep
GROUP BY id
Although this is not MySQL nor SQL per se, it might help to do it in MySQL or SQL.

MYSQL Join/Index optimization

I have a query that tries to find all shopping carts containing a set of given packages.
For each package I join the corresponding cartitem table once, because I am only interested in carts containing all given packages.
When I reach more than 15 packages(joins) the query performance rapidly drops.
I have two indeces on the corresponding foreign columns and am aware that mysql uses only one of them. When I add an index over the 2 columns(cartitem_package_id,cartitem_cart_id) it works, but is this the only way to solve this situation?
I would like to know why MYSQL suddently stucks in this situation and what may be the mysql internal problem, because I do not see any deeper problem with this definition and query? Does that may be an issue with the query optimizer and can I do something(e.g. adding brackets) to support or force a specific query execution? Or has anyone a different approach here, using another query?
The query looks something like this:
SELECT cart_id
FROM cart
INNER JOIN cartitem as c1 ON cart_id=c1.cartitem_cart_id AND c1.cartitem_package_id= 7
INNER JOIN cartitem as c2 ON cart_id=c2.cartitem_cart_id AND c2.cartitem_package_id= 8
INNER JOIN cartitem as c3 ON cart_id=c3.cartitem_cart_id AND c3.cartitem_package_id= 9
INNER JOIN cartitem as c4 ON cart_id=c4.cartitem_cart_id AND c4.cartitem_package_id= 10
INNER JOIN cartitem as c5 ON cart_id=c5.cartitem_cart_id AND c5.cartitem_package_id= 11
INNER JOIN cartitem as c6 ON cart_id=c6.cartitem_cart_id AND c6.cartitem_package_id= 12
INNER JOIN cartitem as c7 ON cart_id=c7.cartitem_cart_id AND c7.cartitem_package_id= 13
INNER JOIN cartitem as c8 ON cart_id=c8.cartitem_cart_id AND c8.cartitem_package_id= 14
INNER JOIN cartitem as c9 ON cart_id=c9.cartitem_cart_id AND c9.cartitem_package_id= 15
INNER JOIN cartitem as c10 ON cart_id=c10.cartitem_cart_id AND c10.cartitem_package_id= 16
INNER JOIN cartitem as c11 ON cart_id=c11.cartitem_cart_id AND c11.cartitem_package_id= 17
INNER JOIN cartitem as c12 ON cart_id=c12.cartitem_cart_id AND c12.cartitem_package_id= 18
INNER JOIN cartitem as c13 ON cart_id=c13.cartitem_cart_id AND c13.cartitem_package_id= 19
INNER JOIN cartitem as c14 ON cart_id=c14.cartitem_cart_id AND c14.cartitem_package_id= 20
INNER JOIN cartitem as c15 ON cart_id=c15.cartitem_cart_id AND c15.cartitem_package_id= 21
INNER JOIN cartitem as c16 ON cart_id=c16.cartitem_cart_id AND c16.cartitem_package_id= 22
INNER JOIN cartitem as c17 ON cart_id=c17.cartitem_cart_id AND c17.cartitem_package_id= 23
Output:
No result.
Consider the following sample structure:
CREATE TABLE IF NOT EXISTS `cart` (
`cart_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cart_state` smallint(20) DEFAULT NULL,
PRIMARY KEY (`cart_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=80 ;
INSERT INTO `cart` (`cart_id`, `cart_state`) VALUES
(1, 0),(2, 5),(3, 0),(4, 0),(5, 0),(6, 0),(7, 0),(8, 0),(9, 0),(10, 0),(11, 0),(12, 0),(13, 0),(14, 5),(15, 5),(16, 10),(17, 0),(18, 10),(19, 40),(20, 10),(21, 5),(22, 0),(23, 10),(24, 10),(25, 0),(26, 10),(27, 5),(28, 5),(29, 0),(30, 5),(31, 0),(32, 0),(33, 0),(34, 0),(35, 0),(36, 0),(37, 0),(38, 0),(39, 0),(40, 0),(41, 0),(42, 0),(43, 0),(44, 0),(45, 40),(46, 0),(47, 0),(48, 1),(49, 0),(50, 5),(51, 0),(52, 0),(53, 5),(54, 5),(55, 0),(56, 0),(57, 10),(58, 0),(59, 0),(60, 5),(61, 0),(62, 0),(63, 10),(64, 0),(65, 5),(66, 5),(67, 10),(68, 10),(69, 0),(70, 0),(71, 10),(72, 0),(73, 10),(74, 0),(75, 10),(76, 0),(77, 10),(78, 0),(79, 10);
CREATE TABLE IF NOT EXISTS `cartitem` (
`cartitem_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cartitem_package_id` int(10) unsigned DEFAULT NULL,
`cartitem_cart_id` int(10) unsigned DEFAULT NULL,
`cartitem_price` decimal(7,2) NOT NULL DEFAULT '0.00',
PRIMARY KEY (`cartitem_id`),
KEY `cartitem_package_id` (`cartitem_package_id`),
KEY `cartitem_cart_id` (`cartitem_cart_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=89 ;
INSERT INTO `cartitem` (`cartitem_id`, `cartitem_package_id`, `cartitem_cart_id`, `cartitem_price`) VALUES
(1, 4, 2, 200.00),(2, 7, 3, 30.00),(3, 14, 9, 255.00),(4, 14, 9, 255.00),(5, 22, 9, 120.00),(6, 22, 9, 120.00),(7, 13, 13, 300.00),(8, 13, 13, 300.00),(9, 7, 14, 450.00),(10, 13, 14, 250.00),(11, 17, 14, 150.00),(12, 7, 15, 450.00),(13, 13, 15, 250.00),(14, 18, 15, 127.50),(15, 7, 16, 450.00),(16, 17, 16, 150.00),(17, 7, 18, 450.00),(18, 7, 19, 450.00),(19, 17, 19, 150.00),(20, 21, 19, 25.00),(21, 13, 20, 300.00),(22, 7, 21, 550.00),(23, 19, 21, 105.00),(24, 22, 21, 120.00),(25, 17, 22, 150.00),(26, 7, 23, 550.00),(27, 11, 24, 245.00),(31, 7, 26, 450.00),(32, 21, 26, 25.00),(33, 21, 26, 25.00),(34, 22, 26, 120.00),(35, 23, 26, 120.00),(36, 10, 27, 382.50),(37, 22, 27, 120.00),(38, 13, 27, 250.00),(39, 10, 28, 297.50),(43, 7, 29, 550.00),(41, 20, 28, 82.50),(42, 22, 28, 120.00),(44, 7, 30, 550.00),(46, 22, 30, 120.00),(47, 23, 30, 120.00),(48, 21, 18, 25.00),(49, 21, 19, 25.00),(50, 17, 37, 150.00),(51, 17, 37, 150.00),(52, 21, 37, 25.00),(53, 21, 37, 25.00),(54, 4, 45, 1.20),(55, 6, 45, 0.00),(56, 7, 47, 450.00),(57, 4, 50, 200.00),(58, 13, 52, 250.00),(59, 13, 19, 300.00),(60, 9, 19, 0.00),(61, 17, 53, 150.00),(62, 7, 53, 450.00),(63, 22, 18, 120.00),(64, 7, 16, 450.00),(65, 7, 54, 450.00),(66, 7, 57, 450.00),(67, 17, 57, 150.00),(68, 7, 56, 450.00),(69, 17, 59, 150.00),(70, 7, 60, 450.00),(71, 17, 61, 150.00),(72, 17, 63, 150.00),(73, 21, 65, 25.00),(74, 7, 66, 450.00),(75, 7, 67, 450.00),(76, 11, 68, 385.00),(77, 7, 71, 450.00),(78, 11, 73, 385.00),(79, 13, 73, 300.00),(80, 4, 75, 200.00),(82, 7, 73, 30.00),(83, 18, 73, 127.50),(84, 23, 73, 120.00),(85, 7, 73, 30.00),(86, 10, 77, 382.50),(87, 7, 79, 550.00),(88, 17, 79, 150.00);
The given query was a possible edge case leading to no results in this example.
SELECT cart_id
FROM cart
INNER JOIN cartitem as c1 ON cart_id=c1.cartitem_cart_id AND c1.cartitem_package_id= 7
INNER JOIN cartitem as c3 ON cart_id=c3.cartitem_cart_id AND c3.cartitem_package_id= 9
INNER JOIN cartitem as c4 ON cart_id=c4.cartitem_cart_id AND c4.cartitem_package_id= 13
INNER JOIN cartitem as c5 ON cart_id=c5.cartitem_cart_id AND c5.cartitem_package_id= 17
INNER JOIN cartitem as c6 ON cart_id=c6.cartitem_cart_id AND c6.cartitem_package_id= 21
Output:
cart_id
-------------
19
19
The query should return all carts containing items that are connected to packages(7,9,13,17,21) in this case.
My approach to your problem would be:
SELECT
cart_id
FROM
cart
INNER JOIN
cartitem
ON
cart_id = cartitem_cart_id
WHERE
cartitem_package_id IN (7,9,13,17,21) -- items that got to be in the cart
GROUP BY
cart_id
HAVING
count(distinct cartitem_package_id) = 5 -- number of different packages
;
DEMO with your data
Explanation
The principle is to filter first with the list of the desired values, here your packages. Now count the different packages per cart (GROUP BY cart_id). If this count matches the number of values in your filter list, then every single package must be in this cart.
You can replace the value list of the IN clause with a subselect, if you get those values from a subselect.
You should see that this approach should be easy to adapt to similar needs.

How can I assign value to a variable using aggregate function in mysql?

This is my table structure and data.
create table StudentInformation
(
sId INT(5),
name VARCHAR(50),
sClass VARCHAR(10),
maths INT(5),
physics INT(5),
chemistry INT(5)
);
INSERT INTO StudentInformation
values
(1, 'Jai', '11th', 60, 75, 65),
(2, 'Leela', '12th', 91, 87, 94),
(3, 'Suresh', '11th', 75, 68, 70),
(4, 'Ramesh', '11th', 50, 67, 55),
(5, 'Janki', '12th', 78, 89, 78),
(6, 'Lalu', '12th', 30, 38, 45),
(7, 'Amit', '11th', 91, 95, 93),
(8, 'Komal', '11th', 66, 78, 74),
(9, 'Sanjay', '12th', 25, 40, 35);
Now I want to calculate average marks for each class.
I have tried this query :
SELECT
sClass class,
#var := sum(maths+physics+chemistry)/(count(sid)*3) as avgMarksPerSubject,
#var as variableValue,
count(sid) as numberOfStudents
FROM StudentInformation
#where #var > 65
group by sClass;
Use of variable is compulsory here as this is just an example of my actual task.
Now I would like to have those records which have more than 65 marks.
Is it possible by using variable in WHERE clause ?
I am not getting actual data in #var, how can I use it in WHERE clause ?
You can try sql query here.
Any suggestion ?
Thanks
Using a user defined session variable in where clause is only possible when it is pre initialized. Unless otherwise, due to the SQL-Query-Order-of-Operations, the variable will be having a default NULL and the condition may not satisfy the results as expected.
set #var:=0;
SELECT
sClass class,
#var := cast(sum(maths+physics+chemistry)
/(count(sid)*3) as decimal(6,2)
) as avgMarksPerSubject,
#var as variableValue,
count(sid) as numberOfStudents
FROM StudentInformation
where #var < 65
group by sClass
;
+-------+--------------------+---------------+------------------+
| CLASS | AVGMARKSPERSUBJECT | VARIABLEVALUE | NUMBEROFSTUDENTS |
+-------+--------------------+---------------+------------------+
| 11th | 72.13 | 0 | 5 |
| 12th | 60.83 | 0 | 4 |
+-------+--------------------+---------------+------------------+
Here you can clearly see that the variable is not assigned any value per row and from the value calculated in the previous column expression.
You can see its side effects by running the following query:
select * from (
SELECT
sClass class,
#var := cast(sum(maths+physics+chemistry)
/(count(sid)*3) as decimal(6,2)
) as avgMarksPerSubject,
#var as variableValue,
count(sid) as numberOfStudents
FROM StudentInformation
group by sClass
) r where avgMarksPerSubject > 65
+-------+--------------------+---------------+------------------+
| CLASS | AVGMARKSPERSUBJECT | VARIABLEVALUE | NUMBEROFSTUDENTS |
+-------+--------------------+---------------+------------------+
| 11th | 72.13 | 60.83 | 5 |
+-------+--------------------+---------------+------------------+
Example # SQL Fiddle: