SQL with multiple SELECT statement - mysql

Hi I have a bit of a problem with my SQL. My problem is when I filter the dates of my data, my SQL statement only returns 2 records which was the employee_id of the user.
This is the original statement of my working code that I have in filtering dates:
SELECT * FROM `rmguidef_prs`.`payment_report` WHERE DATE(`Report_Timestamp`) = DATE_ADD(CURDATE(), INTERVAL 24 HOUR) AND Employee_ID IN (
SELECT T1.Employee_ID from `rmguidef_prs`.`employee` T1
WHERE T1.Supervisor_ID = '".$id."')
OR Employee_ID = '".$id."'
This is the modified statement that I need the filters: (its working ok)
SELECT * FROM `report` WHERE Employee_ID IN (
SELECT T1.Employee_ID from `employee` T1
WHERE T1.Supervisor_ID = '".$id."')
OR Employee_ID IN (
SELECT T2.Manager_ID from `branches` T2
WHERE T2.Manager_ID = '".$id."')
OR Employee_ID = '".$id."'
But when I add this: DATE(Timestamp) = DATE_ADD(CURDATE(), INTERVAL 24 HOUR) in the statement to filter the date the only records shown are coming from this: OR Employee_ID = '".$id."'
SELECT * FROM `report` WHERE DATE(`Timestamp`) = DATE_ADD(CURDATE(), INTERVAL 24 HOUR) AND Employee_ID IN (
SELECT T1.Employee_ID from `employee` T1
WHERE T1.Supervisor_ID = '".$id."')
OR Employee_ID IN (
SELECT T2.Manager_ID from `branches` T2
WHERE T2.Manager_ID = '".$id."')
OR Employee_ID = '".$id."'
I want my modified SQL statement to be filtered by today's date, week, month, and past 3 months. I already have to code for those filters but I cannot figure out how to add those to my statement.

Add parenthesis to group criteria:
SELECT *
FROM `report`
WHERE DATE(`Timestamp`) = DATE_ADD(CURDATE(), INTERVAL 24 HOUR)
AND ( Employee_ID IN (SELECT T1.Employee_ID
FROM `employee` T1
WHERE T1.Supervisor_ID = '".$id."'
)
OR Employee_ID IN (SELECT T2.Manager_ID
FROM `branches` T2
WHERE T2.Manager_ID = '".$id."'
)
OR Employee_ID = '".$id."'
)
AND takes precedence over OR, so your date criteria was only being considered for the first of the three Employee_ID criteria.
Edit: After re-reading your question I'm not entirely sure if the above is what you're after, your date criteria would only return records with tomorrow's date, which probably doesn't exist in the Timestamp field, so that's probably the real problem.

Related

How to change format of the MySQL result?

I have a complex mysql query language, including several sub queries and my final result is as below. There is something that I am dealing with it and I can't solve it and this is a way result is being presented. I am wondering to know how can i change the structure of the result in a way that the result is being presented only in one row and I don't want to see NULL fields. I mean something like below
This is mysql query
select count(*) as userRetentionSameDay, null as 'userRetentionDiffDay' from (SELECT date(`timestamp`), `user_xmpp_login`
FROM table1
WHERE DATE(`timestamp` ) = CURDATE() - INTERVAL 1 DAY) as res1
right join (select date(ts), user
from table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
and product_id REGEXP ("^(europe+$" )) as lej1
on lej1.user = res1.`user_xmpp_login`
where res1.`user_xmpp_login` IS not NULL
union all
select null as 'userRetentionSameDay', count(*) as userRetentionDiffDay from (SELECT date(`timestamp`), `user_xmpp_login`
FROM table1
WHERE DATE(`timestamp` ) = CURDATE() - INTERVAL 1 DAY) as res1
right join (select date(ts), user
from table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
and product_id REGEXP ("^(europe+$" )) as lej2
on lej2.user = res1.`user_xmpp_login`
where res1.`user_xmpp_login` IS NULL;
What are the recommended solutions to doing that?
try this.
SELECT A.userRetentionSameDay,B.userRetentionDiffDay FROM (
SELECT COUNT() AS userRetentionSameDay FROM
(
SELECT DATE(timestamp), user_xmpp_login
FROM table1
WHERE DATE(timestamp ) = CURDATE() - INTERVAL 1 DAY) AS res1
RIGHT JOIN (SELECT DATE(ts), USER
FROM table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
AND product_id REGEXP ("^(europe+$" )) AS lej1
ON lej1.user = res1.user_xmpp_login
WHERE res1.user_xmpp_login IS NOT NULL
) A,
(
SELECT COUNT() AS userRetentionDiffDay FROM (
SELECT DATE(timestamp), user_xmpp_login
FROM table1
WHERE DATE(timestamp ) = CURDATE() - INTERVAL 1 DAY
) AS res1
RIGHT JOIN (SELECT DATE(ts), USER
FROM table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
AND product_id REGEXP ("^(europe+$" )
) AS lej2
ON lej2.user = res1.user_xmpp_login
WHERE res1.user_xmpp_login IS NULL
) B;

MySql : Get data from two tables

I am stuck with mysql query.Not able to proceed.
I have 2 tables where user's login time is recorded.Login time should be considered when either of the table contains entry. I want to find userwise sum of logins for a month.
I could reach till here. But not able to understand how to get sum
select table1.employeeId
, date(table1.loginTime) as date1
, date(table2.loginTime) as date2
from table1
inner join table2 on table1.employeeId=table2.employeeId
and table1.loginTime>='2017-01-01 00:00:00'
and table1.loginTime<='2017-01-31 23:59:59'
and table2.loginTime>='2017-01-01 00:00:00'
and table2.loginTime<='2017-01-31 23:59:59'
For ex : count=0
employe1 logged
on 1-Jan-2017 in table1 & table2 <- count++ (if he logs in 2 tables then only 1 count should be considered)
on 2-Jan-2017 in table1 <- count++
So for employee1 count is 2
You could do this with outer joins, but it would be needlessly complex:
select employeeId
, count(*) as loginCount
from ( select employeeId
, loginTime
from table1
where loginTime between '2017-01-01 00:00:00'
and '2017-01-31 23:59:59'
union
select employeeId
, loginTime
from table2
where loginTime between '2017-01-01 00:00:00'
and '2017-01-31 23:59:59'
( as a
group by employeeId;
Another approach:
SELECT
employeeId,
COUNT(1)+
(
SELECT COUNT(1)
FROM TABLE2 T2
WHERE MONTH(T2.loginTime) = 1
AND YEAR(T2.loginTime) = 2017
AND T2.employeeId = T1.employeeId
)
AS LOGINTIMES
FROM
TABLE1 T1
WHERE MONTH(loginTime) = 1
AND YEAR(loginTime) = 2017
GROUP BY employeeId
Sample fiddle: http://sqlfiddle.com/#!9/45ce27/3/0

MySQL Update with same table subquery

I have a table (EMP_ID, START_DATE, END_DATE) that contains a series of date ranges. What I want to do is ensure that they are all contiguous, so the END_DATE should be one less than the next START_DATE for any given EMP_ID.
I have the following query that lets me identify the records that are not contiguous:
SELECT H.EMP_ID,
H.START_DATE,
H.END_DATE,
DATE(
( SELECT MIN(START_DATE)
FROM TSRHierarchy I
WHERE I.START_DATE > H.START_DATE
AND I.EMP_ID = H.EMP_ID
)
) AS NEXT_DATE
FROM TSRHierarchy H
HAVING END_DATE <> DATE_ADD(NEXT_DATE, INTERVAL -1 DAY)
ORDER BY H.EMP_ID, H.START_DATE;
What I can't do is figure out how to turn this into an UPDATE statement? The MySQL documentation states 'Currently, you cannot update a table and select from the same table in a subquery.' which may be part of my problem.
Any suggestions for a work-around?
Try this UPDATE query using JOIN
UPDATE TSRHierarchy t
JOIN
( SELECT H.EMP_ID,
H.START_DATE,
H.END_DATE,
DATE((SELECT MIN(START_DATE)
FROM TSRHierarchy I
WHERE I.START_DATE > H.START_DATE
AND I.EMP_ID = H.EMP_ID
)) AS NEXT_DATE
FROM TSRHierarchy H
HAVING END_DATE <> DATE_ADD(NEXT_DATE, INTERVAL -1 DAY)
) AS t2
ON t.EMP_ID = t2.EMP_ID
SET t.END_DATE = t2.NEXT_DATE

mysql multiple tables select last 7 days

I am having 3 tables, containing some records which have a date and a numeric value (the tables can't be merged). I want to make up a bar chart using the information from the tables. The bar chart is grouped by days and should display the last seven days.
Earlier i had two tables and used the following query-scheme:
SELECT
t.credits1,
t.credits2,
t.date
FROM
(
(
SELECT
t1.credits1,
t2.credits2,
t1.date
FROM
(
SELECT
SUM(credits) AS credits1,
date
FROM
table1
WHERE
table1.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table1.date)
) t1
LEFT JOIN
(
SELECT
SUM(credits) AS credits2,
date
FROM
table2
WHERE
table2.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table2.date)
) t2
ON t1.date = t2.date
)
UNION
(
SELECT
t1.credits1,
t2.credits2,
t1.date
FROM
(
SELECT
SUM(credits) AS credits1,
date
FROM
table1
WHERE
table1.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table1.date)
) t1
RIGHT JOIN
(
SELECT
SUM(credits) AS credits2,
date
FROM
table2
WHERE
table2.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table2.date)
) t2
ON t1.date = t2.date
)
) t GROUP BY
DATE(date)
(pseudo code)
But how can i do this with more than 2 tables?
Is there any chance to set the dates of the past 7 days as a base, so that i get 7 records everytime?
To point out the problem: If I dont have records in the first table for a day, i won't get the records from the other tables for that day.
I assume the 3 tables have similar schemas? Try using UNION ALL to join the tables together.
SELECT ABB1.date, SUM(ABB1.credit) AS daily_total
FROM
(SELECT date, credits
FROM table1
UNION ALL
SELECT date, credits
FROM table1
UNION ALL
SELECT date, credits
FROM table2) AS ABB1
WHERE DATE >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)

Select the first element in each day of the month

How to select the first element of each day in a month with mysql query ?
I have table with offers - startdate, so i can check for each day,month,year i'm getting the element but, i'm wondering how to get only the first element in each day of some month ?
Assume the following
Table is called mytable
Table has id as primary key
Table has dt as datatime
You want the first id of everyday in February 2012
Try this:
SELECT B.id FROM
(
SELECT DATE(dt) date_dt,MIN(dt) dt
FROM mytable
WHERE dt >= '2012-02-01 00:00:00'
AND dt < '2012-03-01 00:00:00'
GROUP BY DATE(dt)
) A
LEFT JOIN mytable B USING (dt);
If any dt has multiple B.id values try this:
SELECT dt,MIN(id) id
(
SELECT B.id,B.dt FROM
(
SELECT DATE(dt) date_dt,MIN(dt) dt
FROM mytable
WHERE dt >= '2012-02-01 00:00:00'
AND dt < '2012-03-01 00:00:00'
GROUP BY DATE(dt)
) A
LEFT JOIN mytable B USING (dt)
) AA GROUP BY dt;
Assuming startdate is a DATETIME type, and the earliest entry is the one with the earliest DATETIME value, for March, 2012:
SELECT DISTINCT *
FROM tbl t1
LEFT JOIN tbl t2
ON (t2.startdate BETWEEN '2012-02-01 00:00:00' AND '2012-02-29 23:59:59')
AND t2.startdate < t1.startdate
WHERE (t1.startdate BETWEEN '2012-02-01 00:00:00' AND '2012-02-29 23:59:59')
AND t2.startdate IS NULL
If there are no duplicate dates, then you don't need the DISTINCT.
This query works by joining with any earlier record for the same month, so if nothing was joined, it's the earliest, through process of elimination.
This technique is explained in detail in the book SQL Antipatterns.
This could also be solved with subqueries, but this type of JOIN is supposed to be easier to optimize by MySQL than subqueries, which often negate the use of indexes.
without knowing the exact structure of your table something like this should work:
SELECT MIN(offerId) FROM offers WHERE startdate <= '2012-03-06' AND startdate >= '2012-02-06' GROUP BY date(startdate)
It sounds like you are trying to do something like the following:
SELECT col_1, date_col, col_3 FROM tbl
WHERE
date_col = ( SELECT min(date_col) FROM tbl
WHERE
year(date_col) = 2006 AND
month(date_col) = 02
);
This can also be used to find the max( date_col ) . Hope this helps.
Just to offer a different way to skin this cat (much easier in SQL Server for once actually)
SELECT
t0.offerId
FROM
offers AS t0 LEFT JOIN
offers AS t1 ON t0.offerId = t1.offerId AND t1.startDate > t0.startDate AND
(t0.startDate BETWEEN '2012-02-01' AND '2012-03-01') AND
(t1.startDate BETWEEN '2012-02-01' AND '2012-03-01')
WHERE
t1.col1 IS NULL;
If you have multiple rows with the same exact time you will get multiple values returned, which you can weed out in your application logic or with a sub-query. BTW this is called a groupwise minimum/maximum.