MySQL aggregation - mysql

Hi all I am trying to aggregate the number of searches that clients are doing. I currently have this working for 1 day. I would also like to put in a column for searches for that week, month, year and total
USE live_travelcoglog;
SELECT lu.Name, lu.UID, IFNULL(l.AgentId, 'CP Total') AS "CP", COUNT(*) AS "DateTotal", MAX(l.Submitted) AS "LastSearchTime"
FROM logs l INNER JOIN live_travelcog.users lu ON l.ChannelPartnerId = lu.CustId
WHERE Submitted BETWEEN '2014-04-23 00:00:00' AND '2014-04-23 23:59:59'
AND l.MessageType = 'COG_HotelAvail_RS'
GROUP BY lu.Name, l.AgentId ASC WITH ROLLUP;
Now I can run the queries for the different values that I am after but I am sure there is a nicer way that they can all be grouped together. If someone could kindly point me in the right direction it would be greatly appreciated.
Thanks
Daz

Is this the sort of thing you were looking for?
USE live_travelcoglog;
SELECT
lu.Name,
lu.UID,
IFNULL(l.AgentId, 'CP Total') AS "CP",
SUM(Submitted BETWEEN '2014-04-23 00:00:00' AND '2014-04-23 23:59:59') AS DateTotal,
SUM(Submitted BETWEEN '2014-04-17 00:00:00' AND '2014-04-23 23:59:59') AS WeekTotal,
SUM(Submitted BETWEEN '2014-04-01 00:00:00' AND '2014-04-23 23:59:59') AS MonthTotal,
MAX(l.Submitted) AS "LastSearchTime"
FROM logs l
INNER JOIN live_travelcog.users lu
ON l.ChannelPartnerId = lu.CustId
WHERE
l.MessageType = 'COG_HotelAvail_RS'
GROUP BY
lu.Name,
l.AgentId ASC
WITH ROLLUP;

Related

How to get latest results by date when selecting from two table?

I have two tables and I would like to join then with a query.
result save the actual entry of results
user_tracking tracks the acceptance and completion of work, users can cancel and accepts work again at a later time.
SELECT *
from
svr1.result r,
svr1.user_tracking u
where
r.uid = u.user_id and r.tid = u.post1
and u.function_name = '7' #7 == accept work
and r.insert_time > '2015-09-23 00:00:00' and r.insert_time < '2015-10-03 00:00:00'
and u.track_time > '2015-09-23 00:00:00' and u.track_time < '2015-10-03 00:00:00'
my result table had 1785 records within the period I wanted to track
but the above query returns 1990 records. I would like to know how can i filter to get the latest date accepted by user only.
in result table: uid,INT, tid,INT, result,VARCHAR and insert_time,TIMESTAMP
in user_tracking table: user_id,INT, post1,VARCHAR function_name,VARCHAR, result,VARCHAR and track_time,TIMESTAMP
the user_tracking function sample records, in this query the track time will change and the rest will remain the same.
Use the GROUP BY command with a MAX() on the required date, this will select the latest date of all the options (assuming all the other columns are equal). Code as follows (need to declare all columns because of the MAX unfortunately):
SELECT r.uid,
r.tid,
r.result,
r.insert_time,
u.user_id,
u.post1,
u.function_name,
u.result,
MAX(track_time)
FROM
svr1.result r,
svr1.user_tracking u
WHERE
r.uid = u.user_id AND r.tid = u.post1
AND u.function_name = '7' #7 == accept work
AND r.insert_time > '2015-09-23 00:00:00' AND r.insert_time < '2015-10-03 00:00:00'
AND u.track_time > '2015-09-23 00:00:00' AND u.track_time < '2015-10-03 00:00:00'
GROUP BY
r.uid,
r.tid

what is difference between these two Date_Format function in MySql query?

select .....
where
a.DateCreated between '2014-01-01 00:00:00' and '2015-01-31 23:59:59'
group by a.StoreID , b.ProductID , DATE_FORMAT(a.DateCreated, '%m')
and
select ....
where
a.DateCreated between '2014-01-01 00:00:00' and '2015-01-31 23:59:59'
group by a.StoreID , b.ProductID , DATE_FORMAT(a.DateCreated, '%Y-%m')
the first is just month
and you get a maximum of 12 rows for each combination of a.StoreID ,
b.ProductID in the result
the second is year and month (this is probably better by the way)
and you get 12 monthly rows for each year and each combination of a.StoreID ,b.ProductID in the result
however!
do NOT use between for date rage filtering, and do NOT use 23:59:59 as the end of the day because it isn't, a much better way is:
where a.DateCreated >= '2014-01-01 00:00:00'
and a.DateCreated < '2016-01-01 00:00:00'

MySQL Union Operator not behaving as expected

I usually find the answer to my questions here. If not, I know that is probably because I haven't looked deep enough. However this time none of the answers I looked through fit my needs. So here it goes:
I want to use MySQL server to build a report from two tables:
ID Email ID Date Spent
----------------------- ---------------------------
A123 a#test.com A123 3.3.14 2.50
B102 b#test.com A123 7.3.14 3.50
yum yum#a.com B102 4.4.14 7.00
(null) (null)
I want to make a report in which for a given timestamp, eg. from 3.1.2014 to 3.31.14, I get a list of all the ID's of the system with the corresponding amount that they have sent, even if they didn't spend anything.
Therefore from the above tables, let's say we want to retrieve the month of March 2014 (from 3.1.2014 to 3.31.14), I would like to get:
ID Spent
------------------
A123 6.00
B102 7.00
yum NULL
I don't mind to have NULL or 0's for those users that didn't spend any money. So far I have gotten this:
SELECT ID,
sum(Spent) AS Spent
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID
UNION
SELECT users.ID,
NULL AS Spent
FROM users
WHERE users.ID NOT IN
(SELECT expenses.ID
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID)
ORDER BY ID;
You can check the above code in here.
It works as expected, but in the real case of my database, the amount of rows in the result query is greater that the amount of unique rows in users.
I have checked that all the ID's in the expenses table are in the users tables, which is the case. I have tested with:
SELECT ID FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
AND ID NOT IN (SELECT users.ID FROM users);
and it returns an empty set, which is as expected.
I must be missing something, but I have no clue of what. Could someone please give some insights? I am pretty new to MySQL, and maybe there is a better way of doing this.
I think you want a left outer join rather than a union:
SELECT u.ID, sum(e.Spent) AS Spent
FROM users u left outer join
expenses e
on u.id = e.id and
e.date >= '2014-03-01 00:00:00' and
e.date < '2014-03-31 00:00:00'
GROUP BY u.ID;
Note in the data you have in the SQL Fiddle, this will return four rows, because of the NULL valued row in users.
you can do a join of two tables (Users and Expenses) to get the same result (http://sqlfiddle.com/#!2/738ea6/5). This will be much faster and an understandable query.
SELECT expenses.ID,
sum(Spent) AS Spent
FROM expenses, users
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
AND users.ID = expenses.ID
GROUP BY expenses.ID
ORDER BY ID;
Group by in second query?
SELECT ID,
sum(Spent) AS Spent
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID
UNION
SELECT users.ID,
NULL AS Spent
FROM users
WHERE users.ID NOT IN
(SELECT expenses.ID
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID)
GROUP BY ID
ORDER BY ID;

Select sum of payments in period where first payment was made in that period

I have table of payments 'user_id - created - price'.
I need to calculate sum of all payments made in period 14-16 of March where first payment was made in the same period
The best solution I came by is
SELECT user_id, SUM(price/100) FROM payment WHERE
(DATE(created) BETWEEN '2014-03-14' AND '2014-03-16')
AND (MIN(created) BETWEEN '2014-03-14 00:00:01' AND '2014-03-16 23:59:59')
GROUP BY user_id
but I got "Invalid use of group function"
Update:
This request solved my problem
SELECT p.user_id, SUM(p.price/100) FROM payment p WHERE
(DATE(created) BETWEEN '2014-03-14' AND '2014-03-16')
AND (SELECT MIN(DATE(created)) FROM payment WHERE user_id = p.user_id) BETWEEN '2014-03-14' AND '2014-03-16'
GROUP BY p.user_id
You can't use MIN() function in where clause,you need to use HAVING to filter on aggregate functions you can rewrite your query as below
SELECT user_id, SUM(price/100)
FROM payment
WHERE
created BETWEEN '2014-03-14 00:00:00' AND '2014-03-16 23:59:59'
GROUP BY user_id
HAVING MIN(created) BETWEEN '2014-03-14 00:00:00' AND '2014-03-16 23:59:59'

Replace sub select counts with a more efficient method

I appear to be having a little spazzy moment today and can't seem to come up with a better way of doing sub select counts on a table.
Basically what I need to do is for each distinct supplier I then need 2 counts (from the same table) one for the total records assigned to that supplier and one for disputed records for that supplier. At the moment I have the query below which is technically correct but slow as hell on a table with 1 mill + records. I'm sure there's a better way of doing it but I can't for the life of me work it out this morning.
SELECT
DISTINCT tblsuppliers.SupplierName,
(SELECT COUNT(*) FROM tblmovements a WHERE m.Supplier=a.Supplier AND a.TicketStatus IN(0,1) AND a.DateRequired>='2013-09-01 00:00:00' AND a.DateRequired<='2013-11-30 23:59:59') as 'Total Tickets',
(SELECT COUNT(*) FROM tblmovements b WHERE m.Supplier=b.Supplier AND b.TicketStatus IN(0,1) AND b.DateRequired>='2013-09-01 00:00:00' AND b.DateRequired<='2013-11-30 23:59:59' AND (b.SuppIsDisputed=1 OR b.SuppDisputeClearedBy>0)) as 'Total Disputed'
FROM tblmovements m
INNER JOIN tblsuppliers ON m.Supplier=tblsuppliers.ID
ORDER BY tblsuppliers.SupplierName ASC
The joined table is just to give me an supplier name as opposed to the supplier ID which is stored in the movements table. Any suggestions are greatly appreciated.
Try this:
SELECT s.SupplierName,
SUM(CASE WHEN m.TicketStatus IN(0,1) AND m.DateRequired>='2013-09-01 00:00:00' AND
m.DateRequired<='2013-11-30 23:59:59' THEN 1 ELSE 0
END) AS 'Total Tickets',
SUM(CASE WHEN m.TicketStatus IN(0,1) AND m.DateRequired>='2013-09-01 00:00:00' AND
m.DateRequired<='2013-11-30 23:59:59' AND
(m.SuppIsDisputed=1 OR m.SuppDisputeClearedBy>0) THEN 1 ELSE 0
END) AS 'Total Disputed'
FROM tblmovements m
INNER JOIN tblsuppliers s ON m.Supplier=s.ID
GROUP BY s.ID
ORDER BY s.SupplierName ASC
SELECT
tblsuppliers.SupplierName,
SUM(IF(TicketStatus IN(0,1) AND DateRequired>='2013-09-01 00:00:00' AND DateRequired<='2013-11-30 23:59:59', 1, 0)) as 'Total Tickets',
SUM(IF(TicketStatus IN(0,1) AND DateRequired>='2013-09-01 00:00:00' AND DateRequired<='2013-11-30 23:59:59' AND (SuppIsDisputed=1 OR SuppDisputeClearedBy>0), 1, 0)) as 'Total Disputed'
FROM tblmovements m
INNER JOIN tblsuppliers ON m.Supplier=tblsuppliers.ID
GROUP BY tblsuppliers.SupplierName