Grand total of Columns using Sum (if) in mysql - mysql

I am trying to calculate the grand total of columns I just created with a SUM (if). I have a table with several product numbers but I want to get totals for specific products only. This is my query:
Select date(orders.OrderDate) As Date,
Sum(If((orders.ProductNumber = '1'), orders.Qty, 0)) As `Product 1`,
Sum(If((orders.ProductNumber = '2'), orders.Qty, 0)) As `Product 2`,
Sum(If((orders.ProductNumber = '3'), orders.Qty, 0)) As `Product 3`,
From orders
Group By date(orders.OrderDate)
I get the totals for each product in columns as expected, but when I try to get the grand total (Product 1 + product 2 + Product 3) using Sum(orders.Qty) as Total, I get the SUM of ALL products in the table and not only the 3 I am looking for.
How can I get the SUM(Product 1 + Product 2 + Product 3)?
Thank you

Try this:
SELECT DATE(o.OrderDate) AS date,
SUM(IF(o.ProductNumber = '1', o.Qty, 0)) AS `Product 1`,
SUM(IF(o.ProductNumber = '2', o.Qty, 0)) AS `Product 2`,
SUM(IF(o.ProductNumber = '3', o.Qty, 0)) AS `Product 3`,
SUM(IF(o.ProductNumber IN ('1', '2', '3'), o.Qty, 0)) AS `Total`
FROM orders o
GROUP BY DATE(o.OrderDate)

Simply pre-cutting rows other than 1, 2, 3. This is faster when ProductNumber is INDEXed column.
SELECT DATE(orders.OrderDate) AS Date,
SUM(IF((orders.ProductNumber = '1'), orders.Qty, 0)) AS `Product 1`,
SUM(IF((orders.ProductNumber = '2'), orders.Qty, 0)) AS `Product 2`,
SUM(IF((orders.ProductNumber = '3'), orders.Qty, 0)) AS `Product 3`,
SUM(orders.Qty) AS Total
FROM orders
WHERE
orders.ProductNumber IN ('1', '2', '3')
GROUP BY DATE(orders.OrderDate)

Related

SQL query to get number of clients with last statement equal connected

I need to make a SQL query
table 'records' structure:
contact_id(integer),
client_id(integer),
worker_id(integer),
statement_status(varchar),
contact_ts(timestamp)
It has to show the following:
current date
number of clients which last statement_status was 'interested'
number of clients which last statement_status was 'not_interested' and previus status was 'not_present'
Could somebody help?
sample data:
contact_id client_id contact_ts worker_id statement_status
'1', '181', '2017-09-24 03:38:31.000000', '107', 'voicemail'
'2', '72', '2017-09-23 09:32:38.000000', '10', 'not_interested'
'3', '277', '2017-09-22 07:06:16.000000', '119', 'interested'
'4', '36', '2017-09-21 04:39:57.000000', '118', 'not_present'
'5', '33', '2017-09-20 04:12:12.000000', '161', 'voicemail'
'6', '244', '2017-09-19 02:26:30.000000', '13', 'not_interested'
'7', '346', '2017-09-18 02:30:35.000000', '255', 'interested'
'8', '128', '2017-09-17 06:20:13.000000', '52', 'not_present'
'9', '33', '2017-09-16 08:58:02.000000', '188', 'not_present'
'10', '352', '2017-09-15 08:18:40.000000', '324', 'not_interested'
'11', '334', '2017-09-14 04:27:40.000000', '373', 'interested'
'12', '2', '2017-09-13 08:44:40.000000', '40', 'not_present'
'13', '33', '2017-09-12 03:46:16.000000', '252', 'voicemail'
'14', '366', '2017-09-11 04:31:22.000000', '78', 'not_interested'
'15', '184', '2017-09-10 06:08:01.000000', '289', 'interested'
'16', '184', '2017-09-09 05:45:56.000000', '124', 'not_present'
'17', '102', '2017-09-08 07:09:30.000000', '215', 'voicemail'
'18', '140', '2017-09-07 08:09:18.000000', '196', 'not_interested'
'19', '315', '2017-09-06 05:13:40.000000', '242', 'interested'
'20', '268', '2017-09-05 07:41:40.000000', '351', 'not_present'
'21', '89', '2017-09-04 05:32:05.000000', '232', 'voicemail'
desired output:
Time, interested, not-interested
2017-09-10 06:08:01, 5, 5
I tried something with sub queries, but it obviously doesn't work:
SELECT
GETDATE()
,(select count(*)
from record a
where (select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 1) == "interested"
group by a.contact_id)
,(select count(*)
from record a
where (select (select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 2) order by a.contact_ts desc limit 1) == "interested"
and
(select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 1) == "interested"
group by a.contact_id)
from record b;
How should I use the inner selects?
I must write a poem, because most of my post is a code.
So maybe something from "Dead man"?
“Don't let the sun burn a hole in your ass, William Blake. Rise now, and drive your cart and plough over the bones of the dead!”
;)
Try something like this:
WITH status AS (
SELECT DISTINCT client_id,
first_value(statement_status) OVER w1 AS last_status,
nth_value(statement_status, 2) OVER w1 AS prev_status
FROM records
WINDOW w1 AS (PARTITION BY client_id ORDER BY contact_ts DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
)
SELECT CURRENT_DATE(),
SUM(last_status = 'interested') AS interesed,
SUM(last_status = 'not_interested' AND prev_status = 'not_present') AS not_interested
FROM status

Ties on Hall of Fame (group player, max level then max score for each game when month is...)

Need to list a Hall of Fame of best players, the database contains each single game player in different games.
The level has the priority, if the level are the same, check the highest score.
I've a database with user_id, level, score, game and data. Schema here:
CREATE TABLE IF NOT EXISTS `docs` (`user_id` int(6) unsigned NOT NULL,
`level` int(3) unsigned NOT NULL,`game` varchar(30) NOT NULL,
`score` int(5) unsigned NOT NULL,
`data` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `docs` (`user_id`, `level`, `game`, `score`,`data`) VALUES
('1', '7', 'pacman', '8452','2018-02-14 15:00:00'),
('1', '9', 'pacman', '9999','2018-02-10 16:30:00'),
('2', '8', 'pacman', '8500','2018-02-24 17:30:00'),
('1', '10', 'pacman', '9100','2018-02-15 18:30:00'),
('1', '10', 'pacman', '8800','2018-02-15 18:11:00'),
('1', '11', 'snake', '9600','2018-02-14 15:00:00'),
('1', '6', 'snake', '7020','2018-02-11 11:30:00'),
('2', '8', 'snake', '8500','2018-02-24 14:00:00'),
('2', '12', 'snake', '9200','2018-02-25 19:00:00'),
('2', '12', 'snake', '9800','2018-02-25 19:20:00'),
('1', '4', 'pacman', '2452','2018-03-11 15:00:00'),
('1', '6', 'pacman', '4999','2018-03-07 16:30:00'),
('2', '7', 'pacman', '5500','2018-03-02 17:30:00'),
('1', '7', 'pacman', '5100','2018-03-01 18:30:00'),
('1', '3', 'snake', '3600','2018-03-03 15:00:00'),
('1', '5', 'snake', '4220','2018-03-01 11:30:00'),
('2', '5', 'snake', '3900','2018-03-04 14:00:00'),
('2', '5', 'snake', '5200','2018-03-05 19:00:00');
i want retrieve the hall of fame for selected month and game,
for example if i choose pacman on march the result should be:
user level score
2 7 5500
1 7 5100
i tryed this how suggest in other similar topic
select d1.*
from docs d1
left outer join docs d2
on (d1.user_id = d2.user_id and d1.level < d2.level)
where d2.user_id is null
order by level desc;
but i've duplicate levels for same user, then i cant choose the game or the month.
here there is the SQL Fiddle
SELECT x.* FROM docs x
JOIN
(select user_id
, game
, MONTH(data) month
, MAX(score) score
from docs
where game = 'pacman'
and MONTH(data) = 3
group
by user_id
, game
, MONTH(data)
) y
ON y.user_id = x.user_id
AND y.game = x.game
AND y.month = MONTH(x.data)
AND y.score = x.score;
or something like that
after a long work, study and research this is the best solution for me:
SELECT user_id, level, score, game
FROM (
SELECT *,
#rn := IF(user_id = #g, #rn + 1, 1) rn,
#g := user_id
FROM (select #g := null, #rn := 0) x,
docs where game='pacman'
ORDER BY user_id, level desc, score desc, game
) X
WHERE rn = 1 order by level desc, score desc;
the explanation is in this topic Select one value from a group based on order from other columns

How to SUM result both SUMs SQL?

Using this query I try to sum result of both SUM function:
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(result + noresult)
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`
I try to do that in this line:
SUM(result + noresult)
Try this:
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status in ('1', '2'), 1, 0))
from `clients`
where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP)
group by `day`
You can't use alias in select columns name you must repeat the code
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status = '1', 1, 0)) + SUM(if(status = '2', 1, 0)) AS all_result
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`
you must repeat the code because the different SQL clause are processed in a specific order (first from then where then select and and group by .... etc.. ) so at the moment of the select parsing the alias are not available to the sql engine
As several other people have stated, you cannot use aliases in your select statement. However, to keep it cleaner, you could combine both conditions rather than summing both SUM fields.
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status = '1' OR status = '2', 1, 0)) AS newcolumn
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`

Handling MySql Group By

Below is the mysql code
CREATE TABLE pricing
(
`id` INT NOT NULL AUTO_INCREMENT, `cost` FLOAT NOT NULL,
`valid_on` TIMESTAMP NOT NULL, `quantity` INT NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO pricing (`id`, `cost`, `valid_on`, `quantity`) VALUES
(NULL, '4', '2017-01-01 00:00:00', '1'),
(NULL, '4', '2017-01-02 00:00:00', '1'),
(NULL, '4', '2017-01-03 00:00:00', '1'),
(NULL, '5', '2017-01-04 00:00:00', '2'),
(NULL, '5', '2017-01-05 00:00:00', '2'),
(NULL, '4', '2017-01-06 00:00:00', '2'),
(NULL, '4', '2017-01-07 00:00:00', '3'),
(NULL, '5', '2017-01-08 00:00:00', '3'),
(NULL, '5', '2017-01-09 00:00:00', '3'),
(NULL, '4', '2017-01-10 00:00:00', '3'),
(NULL, '4', '2017-01-11 00:00:00', '3'),
(NULL, '4', '2017-01-12 00:00:00', '2'),
(NULL, '5', '2017-01-13 00:00:00', '2'),
(NULL, '5', '2017-01-14 00:00:00', '2');
So when Group By is done on quantity following results are displayed.
select quantity, sum(cost) from pricing GROUP BY quantity
1 - 12
2 - 28
3 - 22
But actually I need something like the below results.
quantity start_date end_date cost
1 2017-01-01 00:00:00 2017-01-03 00:00:00 12
2 2017-01-04 00:00:00 2017-01-06 00:00:00 14
3 2017-01-07 00:00:00 2017-01-11 00:00:00 22
2 2017-01-12 00:00:00 2017-01-14 00:00:00 14
SQL Fiddle Link
Can someone please help me solve this issue...
Try this:
SELECT quantity,
MIN(valid_on) AS start_date, MAX(valid_on) AS end_date,
SUM(cost)
FROM (
SELECT id, cost, valid_on, quantity,
#rn := #rn + 1 AS rn,
#grn := IF(#q = quantity, #grn + 1,
IF(#q := quantity, 1, 1)) AS grp
FROM pricing
CROSS JOIN (SELECT #rn := 0, #q := 0, #grn := 0) AS vars
ORDER BY valid_on, quantity) AS t
GROUP BY rn - grp, quantity
The query uses variables in order to identify islands of consecutive records having the same quantity value. Using the computed grp value, it groups separately each island and calculates start/end dates, as well as the sum of cost.
Demo here
This is a pain to do in MySQL. You need to identify the groups. One method -- which is not particularly efficient -- uses a trick. For each row it counts the number of previous rows where the quantity is different from the given row. This identifies adjacent groups with the same value.
select quantity, sum(cost), min(valid_on) as start_valid_on
from (select p.*,
(select count(*)
from pricing p2
where p2.valid_on < p.valid_on and p2.quantity <> p.quantity
) as grp
from pricing p
) p
group by grp, quantity;

groupby query by year

shipwynum is the primary key for convertship table.
Actually this query getting data correct, for year 2008 only. When i replace 2008 with any other year then also getting data correct for that year. This query display the total records for that year not in TotalCount. TotalCount has always one becoz i have group by with shipwynum.
But i want to get data for 1000 to 2011 separately(instead a particular year like 2008) in this one query and TotalCount should display the counts for every year.
I have this query :=
select
distinct
count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear
from convertship con
left join shipscheduled s on con.shipwynum = s.shipwynum and s.deleted = 'N'
where left(s.deldat,4) > 1000 and left(s.deldat,4) <= 2008 and
left(con.condat,4) > 2008 and
con.deleted = 'N' and
con.wytypid in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18') and
s.wytypid not in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18')
group by con.shipwynum
Any help or ideas would be greatly appreciated.
Thanks a lot.
I think you're trying to count number of rows for each year?
From what i assume,
there is one main table convertship and you want to join convertship to shipscheduled.
Then do the group by on that data according to its left(con.condat,4) value.
select distinct
count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear,
left(con.condat,4) as ConYear
from
convertship con
inner join
shipscheduled s on con.shipwynum = s.shipwynum
where
left(s.deldat,4) > 1000 and
left(s.deldat,4) <= 2008 and
-- left(con.condat,4) > 2008 and
con.deleted = 'N' and
s.deleted = 'N' and
con.wytypid in ('66','10','11','12','13','14','15','16','17','18') and
s.wytypid not in ('66','10','11','12','13','14','15','16','17','18')
group by
left(con.condat,4)
I assume the convertship table is not too big, if not this will not work.
Try:
select count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear
from convertship con
left join shipscheduled s
on con.shipwynum = s.shipwynum and
s.deleted = 'N' and
left(s.deldat,4) > 1000 and
left(s.deldat,4) < left(con.condat,4) and
s.wytypid not in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18')
where con.deleted = 'N' and
con.wytypid in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18') and
group by con.shipwynum, left(s.deldat,4)
Note that since deldat and DeliveryQuarter are neither grouped by nor aggregated, their values in the output will essentially be random (within the DelYear).