MySql Daily Report - mysql

I am trying to get some help fixing my complex query. I am explaining below my situation, thanks.
I have the following two tables:
ACTIVITY TABLE:
ID USER_ID CARD_ID CLOCK
1 123 04675545 4/3/2013 1:07:06 PM
2 123 04675545 4/3/2013 2:08:06 PM
3 124 04675550 4/3/2013 2:07:06 PM
4 124 04675550 4/3/2013 4:07:06 PM
5 124 04675550 4/4/2013 10:07:06 AM
6 124 04675550 4/4/2013 2:00:00 PM
7 124 04675550 4/5/2013 4:07:06 PM
8 124 04675550 4/7/2013 8:00:00 AM
9 124 04675550 4/7/2013 5:00:00 PM
PRICE TABLE:
ID FROMTIME TOTIME PRICEPERHOUR
1 08:00:00 19:59:59 50.00
2 20:00:00 07:59:59 75.00
And the following query:
select a.user_id, date(a.clock), ABS(TIME_TO_SEC(TIMEDIFF(a.clock, b.clock))/3600)*c.PRICEPERHOUR as total from
(Select if((#rn:=#rn+1)%2=0,#rn,#rn-1) As rId, act.* from act
join (select #rn:=-1)a
order by user_Id, clock) a
inner join
(Select if((#rn1:=#rn1+1)%2=0,#rn1,#rn1-1) As rId, act.* from act
join
(select #rn1:=-1)b
order by user_Id, clock) b
ON a.rid=b.rid AND a.id <> b.id
inner join
price c
on
TIME_TO_SEC(a.clock) between TIME_TO_SEC(c.FROMTIME)
AND
TIME_TO_SEC(c.TOTIME)
group by a.user_id, date(a.clock)
And I am getting the following result:
USER_ID DATE(A.CLOCK) TOTAL
123 April, 03 2013 00:00:00+0000 50.8333
124 April, 03 2013 00:00:00+0000 100
124 April, 04 2013 00:00:00+0000 194.0833
124 April, 05 2013 00:00:00+0000 1,994.0833
124 April, 07 2013 00:00:00+0000 1,994.0833
However, I am trying to get this result instead:
USER_ID DATE(A.CLOCK) TOTAL
123 April, 03 2013 00:00:00+0000 50.8333
124 April, 03 2013 00:00:00+0000 100
124 April, 04 2013 00:00:00+0000 194.0833
124 April, 05 2013 00:00:00+0000 50
124 April, 07 2013 00:00:00+0000 450
This is part of a clock system. Each time the user check-in, one entry gets recorded on the database. A correct user behavior will be that it has always a pair record recorded. For example user_id 123 clocks at 1:07:06pm and clocks again at 2:08:06pm. However, in some situations, the user may do it just once (unpaired record on the database) and therefore it should only be charged that particular hour from the record. As an example, user 124 on day 4/5/2013.
I am trying all weekend to get this query working :(. Once I get the correct result, I will add a condition to get only one user_id also, (e.g. where user_id=124).

I think even if you manage to do this there are are some potential design pitfalls:
Can people clock in for more than 1 period per day? If so then 2 records for example
10am and 2pm could total 2hours or 4hours.
What happens if people clock in at 11pm and again at 2am?
From a quick glance I don't think your sql takes into account time periods that span across the 2 different pay rates? You should definitely include this scenario in your test data.
If I was going to implement this I would probably move the logic into code, and simplify the price table by only having one time column like:
TIME, PRICE
00:00, 75.00
08:00, 50.00
20:00, 75.00
Also if a user only has one card you may not need to have card_id and user_id in the activity table.

Related

Displaying only records that don't have an update this month

MySQL and PHP
I am attempting to write a SQL statement that will allow me to identify an individual that has not checked in this month. I am stuck on how to write the code.
I have 2 tables
tbl_cust c
tbl_attend a
SELECT
c.custRFID,
a.attendID,
a.RFID,
a.attendDate,
a.attendStatus,
a.attendStatusCode,
a.attendNotes
FROM
tbl_cust c RIGHT OUTER JOIN tbl_attend a ON c.custRFID = a.RFID
WHERE
MONTH(a.attendDate) <> MONTH(CURDATE()) AND YEAR(a.attendDate) =
YEAR(CURDATE())
The code filters out this month, however, it returns every date prior to this month. I only want to display the names from table c that don't have an entry in table a for this month. I don't need all the records.
-------------------------------------------------------------
ID RFID Date Time Status Status Code
-------------------------------------------------------------
1 01 02 03 E1 2018-01-03 1835 1 1
2 02 02 04 E2 2018-01-06 1235 1 1
3 01 02 03 E1 2018-02-07 1801 1 1
4 02 02 04 E2 2018-02-11 1109 1 1
5 01 02 03 E1 2018-03-03 1835 1 1
6 02 02 04 E2 2018-03-06 1235 1 1
7 01 02 03 E1 2018-04-07 1801 1 1
8 02 02 04 E2 2018-04-11 1109 1 1
9 01 02 03 E1 2018-05-01 1032 1 1
If this was May 16, 2018 the following should be the output:
-----------------------------------------------------------
ID RFID Date Time Status Status Code
-------------------------------------------------------------
8 02 02 04 E2 2018-04-11 1109 1 1
This is only using 2 customers, as the actual table will eventually have over 5,000 customers in it. with at least 1 entry per month. Some will have 3 of 4 entries per month, however, I only want to see those with no entry in the current calendar month. I.e.... If they checked in anytime during the calendar month of May 2018, they should not be displayed on the output.
Thank you in advance.
If you want someone who has ever checked in, then you can use aggregation:
select RFID
from attend a
group by RFID
having max(attendDate) < date_add(curdate(), interval 1 - day(curdate()) day);
I would write this as an EXISTS query:
SELECT
c.custRFID
FROM
tbl_cust c
WHERE NOT EXISTS (SELECT 1 FROM tbl_attend a
WHERE c.custRFID = a.RFID AND
MONTH(a.attendDate) = MONTH(CURDATE()) AND
YEAR(a.attendDate) = YEAR(CURDATE()));
You can do this using LEFT JOIN.
Also, try not to use YEAR(column) & MONTH(column) functions in ON/WHERE clauses as SQL will not be able to use indeces in this case.
Something like this should do the trick:
SELECT
c.custRFID,
a.attendID,
a.RFID,
a.attendDate,
a.attendStatus,
a.attendStatusCode,
a.attendNotes
FROM
tbl_cust c
LEFT JOIN tbl_attend a ON (
c.custRFID = a.RFID
AND a.attendDate > DATE_SUB(LAST_DAY(CURDATE()), INTERVAL 1 MONTH)
AND a.attendDate <= LAST_DAY(CURDATE())
)
WHERE
a.RFID IS NULL

Selecting all rows from tableA and join for each row the matching row from tableB

I have two tables: personal and persoLog. One represents personal and the other represents the log of personal events. The persoLog has a personal_log pointing to the personal table. I use join for this but either it is not working as expected or I know it wrong how to use it. Here are the tables:
ID NAME SECTION
1 joe driver
2 george technic
ID PERSONAL_ID EVENT DATE
1 1 idle November, 26 2014 12:28:52+0000
2 1 drive November, 26 2014 12:28:52+0000
3 1 idle November, 26 2014 12:28:52+0000
4 2 idle November, 26 2014 12:28:52+0000
5 2 idle November, 26 2014 12:28:52+0000
So I want to list the personal and their latest log like here:
ID NAME SECTION EVENT DATE
1 joe driver idle November, 26 2014 12:28:52+0000
2 george technic idle November, 26 2014 12:28:52+0000
I use this query
SELECT p.*, pl.event, pl.date
FROM personal p
RIGHT JOIN persoLog pl
ON p.id = pl.personal_id
I expected to return all personal with the only matching log but I got this instead:
ID NAME SECTION EVENT DATE
1 joe driver idle November, 26 2014 12:40:24+0000
1 joe driver drive November, 26 2014 12:40:24+0000
1 joe driver idle November, 26 2014 12:40:24+0000
2 george technic idle November, 26 2014 12:40:24+0000
2 george technic idle November, 26 2014 12:40:24+0000
What am I doing wrong?
That is the SQLfiddle link for my question:
http://sqlfiddle.com/#!2/da315a/2
Try this:
SELECT p.*,
pl.event, pl.date
FROM personal p
JOIN (
SELECT personal_id,max(date) as LastDate from persoLog
GROUP BY personal_id) x on p.id=x.personal_id
JOIN persoLog pl ON p.id = pl.personal_id
AND pl.date=x.lastDate
However, in your example data, all of the dates are the same in the log table. Fix that and the above should work
I believe this should work:
SELECT p.*, pl.event, pl.date
FROM personal p
LEFT JOIN persoLog pl ON p.id = pl.personal_id
GROUP BY p.id
ORDER BY date DESC

Query in a SQL table

I have the following tables:
http://sqlfiddle.com/#!2/1e991/1
But I have a problem! The output of my query is:
DATE SLOT sum(SUCCESSFUL) SUCCESSFUL PERCENTAGE OTA_NAME USERS_SI
July, 02 2013 00:00:00+0000 2 120 120 41.6667 campana 2 50
July, 02 2013 00:00:00+0000 1 200 200 25 campana 2 50
July, 02 2013 00:00:00+0000 1 150 150 53.3333 campana 3 80
July, 01 2013 00:00:00+0000 2 100 100 20 campana 1 20
July, 01 2013 00:00:00+0000 3 440 440 4.5455 campana 1 20
July, 01 2013 00:00:00+0000 1 700 700 2.8571 campana 1 20
And I need a sum of successful with the same date and campaign, for example, I have in July 1 with campaign 1 three rows, then I need sum the successful of the three rows, and with campaign 2 two rows, then I need sum the successful of the two rows, and with campaign 3 one rows, then I need sum the successful of the one row that is the same.
And finally the percentage is the division between sum(SUCCESSFUL) and USERS_SI
The output that I need is:
DATE SLOT sum(SUCCESSFUL) SUCCESSFUL PERCENTAGE OTA_NAME USERS_SI
July, 02 2013 00:00:00+0000 2 320 120 41.6667 campana 2 50
July, 02 2013 00:00:00+0000 1 320 200 25 campana 2 50
July, 02 2013 00:00:00+0000 1 150 150 53.3333 campana 3 80
July, 01 2013 00:00:00+0000 2 1240 100 20 campana 1 20
July, 01 2013 00:00:00+0000 3 1240 440 4.5455 campana 1 20
July, 01 2013 00:00:00+0000 1 1240 700 2.8571 campana 1 20
Can you help me?
sqlfiddle here
SELECT other.date AS date,
other.slot,
other.successful,
calc.sum_successful,
max((case when (rule.tree_si = dms.tree) then dms.numberResponses end))/successful AS percentage,
other.name AS ota_name,
other.successful AS successful,
max((case when (rule.tree_si = dms.tree) then dms.numberResponses end)) AS users_si
FROM aca_ota_other other
join aca_dms_rules rule on other.name = rule.ota_name
join aca_dms dms on dms.date = other.date and rule.tree_si = dms.tree
join (SELECT name, sum(successful) as sum_successful FROM aca_ota_other GROUP BY name) as calc on other.name = calc.name
GROUP BY
other.date,
other.name,
other.successful
ORDER BY other.date desc
I'm not sure but if i understood well, you need something like this:
I'm sorry, I've made some little changes in your query.
SELECT other.date date,
other.slot,
other.name ota_name,
sum(successful) successful,
dms.numberResponses users_si,
SUM(successful)/dms.numberResponses AS percentage
FROM aca_ota_other other
JOIN aca_dms_rules rule ON other.name=rule.ota_name
JOIN aca_dms dms ON dms.date=other.date AND rule.tree_si=dms.tree
GROUP BY other.date,
other.name
ORDER BY other.date DESC
http://sqlfiddle.com/#!2/1e991/22

Get data from table where date between given date and 1 week back

I have database dbadmin, table - tbl_empreimburse with fields-emp_id,rem_amount,rem_date.
I want to retrieve data which comes from given date to a week back.
I tried this query,
SELECT SUM(rem_amount),DATEADD(dd, -7, "2012-01-10")
FROM tbl_empreimburse
GROUP BY emp_id
HAVING emp_id='5' AND rem_date BETWEEN DATEADD(dd, -7, "2012-01-10") AND "2012-01-10"
It gives me error "FUNCTION dbadmin.DATEADD does not exist". Do I need to convert "2012-01-10" to date format? Any Help, Please?
Try this:
This query gives result as you have specified for employee id 5 and date period of 7 days.
SELECT emp_id, SUM(rem_amount)
FROM tbl_empreimburse
WHERE emp_id='5' AND DATEDIFF('2012-12-31', rem_date) BETWEEN 0 AND 7;
OR
Below query gives you all employee data.
SELECT emp_id, SUM(rem_amount)
FROM tbl_empreimburse
GROUP BY emp_id
HAVING DATEDIFF('2012-12-31', rem_date) BETWEEN 0 AND 7;
Check this *SQLFIDDLE reference out. :)
I am not sure why you are using group by clause here...
Sample date:
ID AMOUNT RDATE
1 3400 January, 01 2012 00:00:00+0000
2 5000 January, 10 2012 00:00:00+0000
3 3000 January, 02 2012 00:00:00+0000
5 1000 January, 05 2012 00:00:00+0000
5 2000 January, 04 2012 00:00:00+0000
2 2000 February, 10 2012 00:00:00+0000
Query:
select * from emp
where id = 5;
here is the query to get sum
select id, sum(amount)
from emp
where rdate between '2012-01-10' - interval 7 day
and '2012-01-10'
and id = 5
;
Results:
all records by employee id = 5
ID AMOUNT RDATE
5 1000 January, 05 2012 00:00:00+0000
5 2000 January, 04 2012 00:00:00+0000
sum of amount by employee id = 5
ID SUM(AMOUNT)
5 3000

MySQL: I want to sum my employees cost and group it by employee and by day

I currently have a table where I record all my employee daily expenses
John Smith 01 JAN 2010 200$
John Smith 01 JAN 2010 50$
John Smith 01 JAN 2010 10$
Lady Gaga 01 JAN 2010 50$
Lady Gaga 01 JAN 2010 20$
John Smith 02 JAN 2010 10$
What I would like to display a table that contains a daily report of all bills:
01 JAN 2010
John Smith: 260$
Lady Gaga: 70$
02 JAN 2010
John Smith: 10$
I really hope my request is understandable and you will be able to help me.
Thank a lot for any advice!
I would use a standard group-by:
select date, name, sum(amount) as total
from mytable
group by 1,2
order by 1,2;
use SUM with GROUP BY , do something like
SELECT date,user,SUM(cost)
FROM mytable
GROUP BY date,user
ORDER BY date