This is my clockin table:
This is my user table:
I want to accepted output in this type:
Try this:
set #start_date='2022-12-30';
set #end_date='2022-12-31';
WITH recursive Date_Ranges AS (
select #start_date as date
union all
select date + interval 1 day from Date_Ranges
where date < #end_date
)
SELECT
new_table.*,
(
SELECT
group_concat(`time`)
FROM
`clockin`
WHERE
`emid`=new_table.`id` AND
`date`=new_table.`date`
) as `time`
FROM
(select * from `user` full join Date_Ranges) as new_table
order by date desc
Related
I am trying to calculate the number of users who have an active subscription on a particular day. I also want information related to the subscription plan they are on. I have a subscriptions table which includes the start date and end date of subscription as well as the plan name. I am using a recursive cte to find out the number of subscribers of different plans on a date range but I am getting the error that the cte table doesn't exist. I am using the following code.
SET #start = (SELECT MIN(start_date) FROM subscriptions);
SET #end = (SELECT MAX(end_date) FROM subscriptions);
WITH cte AS (
SELECT #start dt
UNION ALL
SELECT date_add(dt, interval 1 day) FROM cte
WHERE dt < #end
)
SELECT cte.dt, SUM(CASE WHEN subscriptions.plan_name IS NULL THEN 0 ELSE 1 END) FROM cte
LEFT JOIN subscriptions t
ON cte.dt BETWEEN t.start_date AND t.end_date
GROUP BY cte.dt;
the output should look like this
WITH cte AS (
SELECT #start dt
UNION ALL
SELECT date_add(dt, interval 1 day) FROM cte
WHERE dt < #end
)
You are refering cte in itself, which makes it recursive and needs to be defined as such (WITH RECURSIVE).
This is what you need:
WITH RECURSIVE cte AS (
SELECT #start dt
UNION ALL
SELECT date_add(dt, interval 1 day) FROM cte
WHERE dt < #end
)
This keeps inserting already existing fields although it shouldn't.
BEGIN
INSERT INTO ohrm_attendance_raw_data (punch_time, device_id, card_number)
SELECT punch_time, device_id, card_number
FROM ohrm_attendance_master
WHERE ohrm_attendance_master.punch_time >= DATE_SUB(now(), INTERVAL 1 MONTH)
AND NOT EXISTS (
SELECT 1 FROM ohrm_attendance_record WHERE ohrm_attendance_record.punch_in_user_time = ohrm_attendance_master.punch_time)
AND NOT EXISTS (
SELECT 1 FROM ohrm_attendance_record WHERE ohrm_attendance_record.punch_out_user_time = punch_time);
end
It looks like your field punch_time is datetime type or something like that... so I think your problem is that you are comparing two dates... and what's the problem with that?, that MySQL and other RDBMS compare that including hour, minutes, seconds and miliseconds... so it can make that the comparison be false... You can trunc the date or give it some format:
With DATE function:
BEGIN
INSERT INTO ohrm_attendance_raw_data (punch_time, device_id, card_number)
SELECT punch_time, device_id, card_number
FROM ohrm_attendance_master
WHERE ohrm_attendance_master.punch_time >= DATE_SUB(now(), INTERVAL 1 MONTH)
AND NOT EXISTS (
SELECT 1 FROM ohrm_attendance_record WHERE DATE(ohrm_attendance_record.punch_in_user_time) = DATE(ohrm_attendance_master.punch_time))
AND NOT EXISTS (
SELECT 1 FROM ohrm_attendance_record WHERE DATE(ohrm_attendance_record.punch_out_user_time) = DATE(punch_time));
END
With DATE_FORMAT function:
BEGIN
INSERT INTO ohrm_attendance_raw_data (punch_time, device_id, card_number)
SELECT punch_time, device_id, card_number
FROM ohrm_attendance_master
WHERE ohrm_attendance_master.punch_time >= DATE_SUB(now(), INTERVAL 1 MONTH)
AND NOT EXISTS (
SELECT 1 FROM ohrm_attendance_record WHERE DATE_FORMAT(ohrm_attendance_record.punch_in_user_time, '%d-%b-%Y') = DATE_FORMAT(ohrm_attendance_master.punch_time, '%d-%b-%Y'))
AND NOT EXISTS (
SELECT 1 FROM ohrm_attendance_record WHERE DATE_FORMAT(ohrm_attendance_record.punch_out_user_time, '%d-%b-%Y') = DATE_FORMAT(punch_time,'%d-%b-%Y'));
END
TABLE
Table:
Id Date
1 01-10-15
2 01-01-16
3 01-03-16
4 01-06-16
5 01-08-16
Given two dates startdate 01-02-16 and enddate 01-05-16. I need to get the data from the table such that it returns all data between the closest past date from startdate and closest future date from enddate including the two dates. So the result will look like this.
Result:
Id Date
2 01-01-16
3 01-03-16
4 01-06-16
What I am doing
What I am doing now is fetching the whole data and removing from the array results less than closest fromdate and greater than closest enddate
What I want
What I want is to do this in query itself so that I don't have to fetch the whole data from table each time.
If you column's type is date, use union can do it:
(select * from yourtable where `date` <= '2016-01-02' order by `date` desc limit 1)
-- This query will get record which is closest past date from startdate
union
(select * from yourtable where `date` => '2016-01-05' order by `date` asc limit 1)
-- This query will get record which is closest future date from enddate
union
(select * from yourtable where `date` between '2016-01-02' and '2016-01-05')
Demo Here
Imaging your date is in YYYY-mm-dd
## get rows within the dates
SELECT * FROM tab WHERE ymd BETWEEN :start_date AND :end_date
## get one row closest to start date
UNION
SELECT * FROM tab WHERE ymd < :start_date ORDER BY ymd DESC LIMIT 1
## get one row closest to end date
UNION
SELECT * FROM tab WHERE ymd > :end_date ORDER BY ymd LIMIT 1
Try this
Select *
From
dTable
Where
[Date]
Between
(Select
Max(t1.Date)
From
dTable t1
Where
t1.date <startdate) And
(Select
Min(t2.Date)
From
dTable t2
Where
t2.date >enddate)
If Date is String, STR_TO_DATE and DATEDIFF can be used here.
SELECT id, Date
FROM tab
where
STR_TO_DATE(Date, '%d-%m-%y') BETWEEN('2016-02-01')AND('2016-05-01')
or
id = (SELECT id FROM tab
where STR_TO_DATE(Date, '%d-%m-%y') > '2016-05-01'
ORDER BY DATEDIFF(STR_TO_DATE(Date, '%d-%m-%y'), '2016-05-01') Limit 1)
or
id = (SELECT id FROM tab
where STR_TO_DATE(Date, '%d-%m-%y') < '2016-02-01'
ORDER BY DATEDIFF('2016-02-01', STR_TO_DATE(Date, '%d-%m-%y')) Limit 1)
Hi all i execute this query to get a table where there's statistics of some database information.. i'd like to intialise the fields that don't exist ( because the query is executed in different dates and sometimes there's a day where there's nothing ) so i'd like it to return 0 and NULL ( in TOP column )
SELECT
SUM(IF(`TOP` = 'one',`Nb`,0)) as first_one,
SUM(IF(`TOP` = 'two',`Nb`,0)) as second_one,
SUM(IF(`TOP` = 'three',`Nb`,0)) as thrid_one,
SUM(IF(`TOP` NOT IN ('three','two','one'),`Nb`,0)) as forth_one,
GROUP_CONCAT(IF(`TOP` NOT IN ('three','two','one'),`TOP`,'') SEPARATOR '') as `OR`
FROM (
SELECT
COUNT(*) as Nb,
'one' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
COUNT(*) as Nb,
'two' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND S=0
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
COUNT(*) as Nb,
'three' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND S<>0
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
`Nb`,
`TOP`
FROM(
SELECT
COUNT(*) as Nb ,
`OR` as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY
`OR`
ORDER BY
Nb DESC
LIMIT 1
) as tmp
)as tmp1
Assuming that in tmp1 you have data you need but with "gaps" (days when there were no data at all) you could RIGHT JOIN tmp1 to table tmp2 using day (I assume that you have such column in tmp1 table). So tmp2 would be just list of days:
SELECT '2013-05-17' as day UNION SELECT '2013-05-18' UNION SELECT ...
I could elaborate my answer if you'd like to provide your DB schema.
You can replace each subquery with:
SELECT
IFNULL(tmp.Nb,0) as Nb,
IFNULL(tmp.`TOP`, 'value') as `TOP`
FROM (
--subquery
) as tmp
Example for the first subquery:
SELECT
IFNULL(tmp.Nb,0) as Nb,
IFNULL(tmp.`TOP`, 'one') as `TOP`
FROM (
SELECT
COUNT(*) as Nb,
'one' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
) as tmp
SQL is good at grouping existing entities into categories, but bad at "creating" entities itself. I would advise either a generic number table (really just the numbers from 0 to a few hundredthousand) if you have also non-date categories or as Wiktor suggested a date-Table which gets filled every now and then and has the next few years as well as the time since your program is working.
With a date table
list_dates (
id int(11) not null primary key auto_increment,
dateval date not null
)
you could start your queries from that table (with a reasonable range, of course) and count every thing else:
select list_dates.dateval as date, count(*) as cnt
from list_dates
left join actions on actions.actiontime >= (cast list_dates.date_val as datetime)
and actions.actiontime < (cast list_dates.date_val `interval 1 day as datetime)
where list_dates.dateval between '$fromDate' and '$toDate'
group by list_dates.dateval
;
or starting with a number table numbers
select $fromDate + interval numbers.number day as date, count(*) as cnt
from numbers
left join actions
on actions.actiontime >= (cast $fromDate + interval numbers.number day as datetime)
and actions.actiontime < (cast $fromDate + interval (1 + numbers.number) day as datetime)
where numbers.number >= 0 and numbers.number < $countDates
group by numbers.number
;
One Day
If you really want just that one day (today) then you can of course use a anonymous subselect- Table instead, so it becomes
select list_dates.dateval as date, count(*) as cnt
from ( select curdate() as dateval ) as list_dates
left join actions on actions.actiontime >= (cast list_dates.date_val as datetime)
and actions.actiontime < (cast list_dates.date_val `interval 1 day as datetime)
where list_dates.dateval between '$fromDate' and '$toDate'
group by list_dates.dateval
;
assume we have table
id, title, date
I need to build 1 query to:
select date = TODAY, order by id
select data < TODAY, order by date desc,
select data > TODAY, order by date asc,
I think you need to use UNION and sub queries:
SELECT * FROM (
SELECT *
FROM YourTable
WHERE Date(dateField) = Date(Now())
ORDER BY ID
) t1
UNION
SELECT * FROM (
SELECT *
FROM YourTable
WHERE dateField < Now()
ORDER BY dateField DESC
) t2
UNION
SELECT * FROM (
SELECT *
FROM YourTable
WHERE Date(dateField) > Now()
ORDER BY dateField
) t3
Here is a simplified SQL Fiddle example.
Good luck.