SELECT Name, doB, Age CURDATE( ) , (
YEAR( CURDATE( ) ) - YEAR( F )
) - ( RIGHT( CURDATE( ) , 5 ) < RIGHT( F, 5 ) ) AS Ages
SELECT Name, DoB, Ages WHERE Age=20 As Age
FROM Table_
ORDER BY N
Where do I put the the where AGES=20 if I want to only display the names of people that are 20 years old if the Age column is a temp column?
-- edit --
The oryginal query is:
SELECT N, F, CURDATE( ) ,
( YEAR( CURDATE( ) ) - YEAR( F ) )
- ( RIGHT( CURDATE( ) , 5 ) < RIGHT( F, 5 ) ) AS Age
FROM edad_ LIMIT 0 , 30
I can't make heads or tails of your query.
But to answer your question, a predicate on a derived column is not allowed in a WHERE clause, but it can be included in a HAVING clause. For example:
SELECT t.DoB
, TIMESTAMPDIFF(YEAR, t.DoB, CURDATE()) AS age
FROM mytable t
HAVING age = 20
BUT...
Be aware of performance issues. Note that the HAVING clause is applied very late in the processing of the query, after all of the rows have been retrieved and prepared. It acts more like a filter on the rows that are returned, while the WHERE clause acts as a filter on the rows retrieved, processed much earlier in the query.
For performance on large sets, we typically want to benefit from index range scans, so we use an equivalent predicate on a native column. (If a an appropriate index is available.)
For example, if an index on DoB is available:
SELECT t.DoB
, TIMESTAMPDIFF(YEAR, t.DoB, CURDATE()) AS age
FROM mytable t
WHERE t.DoB >= CURDATE() + INTERVAL -21 YEAR
AND t.DoB < CURDATE() + INTERVAL -20 YEAR
(NOTE: You may need to replace >= with > and replace < with <= to get the age calculation working the way you want on the edge cases of CURDATE is exactly 20 years or exactly 21 years from DoB.)
Related
I am trying to select records that are older than 1 day or 24 hours from a MYSQL DB. I can't figure it out why this statement doesn't work with NOW() and it only works if I explicitly add the date manually, here is the code for your review:
date_posted is setup as "datetime" in the DB table.
Works this way (Not desirable, for testing only)
SELECT count( DISTINCT my_id ) AS 'a'
FROM my_table
WHERE date_posted >= DATE_SUB( '2015-10-03 09:10:19', INTERVAL 24 HOUR )
It should work this way, but it brings a "0" count result:
SELECT count( DISTINCT my_id ) AS 'a'
FROM my_table
WHERE date_posted >= DATE_SUB( NOW(), INTERVAL 24 HOUR )
SELECT count( DISTINCT my_id ) AS 'a'
FROM my_table
WHERE date_posted >= subdate(current_date, 1)
here subdate(current_date, 1) will return your the yesterday date
if your want to select only the yesterday post then use the following
WHERE date_posted = subdate(current_date, 1)
I am trying to retrieve the TIMEDIFF from the last_call field of every row, where TIMEDIFF between current row and next row is greather than 10 min!
Can someone please help? Meybe there is a better way of doing this?
My goal is to get the total of all timediff between severall database entrys but only if they are greather than 10 min.
SELECT DATE_FORMAT( last_call, '%d' ) AS 'day',
(
SELECT TIME_TO_SEC(TIMEDIFF(MAX(cl1.last_call), MIN(cl1.last_call)))
FROM calls AS cl1
WHERE TIME_TO_SEC(TIMEDIFF(MAX(cl1.last_call), MIN(cl1.last_call))) > 600
AND cl1.calling_agent=9
AND EXTRACT(DAY FROM cl1.last_call ) = EXTRACT(DAY FROM calls.last_call )
) AS 'brake'
FROM calls
WHERE calling_agent =9
AND last_call > DATE_SUB( now( ) , INTERVAL 12 MONTH )
GROUP BY EXTRACT( DAY FROM last_call )
I am trying to summarize records using the following query in MySQL. It works great as long as there is at least one record in each year. If records are missing in years, then the year doesn't show up. How can I modify this to show each year within my filter?
SELECT SUM( SICK_SIZE + DEAD_SIZE ) AS Cases, DATE_FORMAT( EVENT_DATE, '%Y' ) AS DateYear
FROM report_case_ext
WHERE DATE_FORMAT( EVENT_DATE, '%Y' ) >= DATE_FORMAT( DATE_ADD( CURDATE( ) , INTERVAL -4YEAR ) , '%Y' )
AND DATE_FORMAT( EVENT_DATE, '%Y' ) <= DATE_FORMAT( CURDATE( ) , '%Y' )
GROUP BY DATE_FORMAT( EVENT_DATE, '%Y' )
In MySQL, you can use sqlvariables, join to any other table to simulate row creation -- which returns a valid result set of the years you are looking for, then LEFT-JOIN to your other table so you know you'll always get the years you want...
select
YearsYouWant.RequireYear as DateYear,
SUM( RCE.SICK_SIZE + RCE.DEAD_SIZE ) AS Cases
from
( select #nYear := #nYear +1 as RequireYear
from report_case_ext,
( select #nYear := year( curdate()) -5 ) sqlvars
limit 5 ) as YearsYouWant
LEFT JOIN
report_case_ext RCE
on YearsYouWant.RequireYear = year( RCE.Event_Date )
GROUP BY
YearsYouWant.RequireYear
The inner prequery that uses "report_case_ext" is only used to have a table of at least 5 records to keep the years you want... In this case,
#nYear is initialized to 1 year less than the 4 you were looking for -- hence -5
curdate() = 2013 - 5 = 2008.
Then, in the select #nYear := #nYear +1 first time will have the first year become 2009 and complete for 5 years, thus generating a record for 2009, 2010, 2011, 2012 and 2013 (via LIMIT 5)
Now that result (of all years) is LEFT-joined to the report_case_ext table on common years. So, even those that have no dates
Create a table contains all possibile year/month/date (depends on your needs).
Then left join the table.
What is the most straightforward way to pad empty dates in sql results (on either mysql or perl end)?
I have table like
CREATE TABLE `survey` (
`id` int(11) NOT NULL auto_increment,
`submitdate` datetime default NULL,
`answer` varchar(5) collate utf8_unicode_ci default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=499 ;
now to get values like
c t Clicks
2012-10-29 2012-10-22 10
2012-11-04 2012-10-30 20
2012-11-11 2012-11-05 30
2012-11-19 2012-11-12 34
I am using this query
SELECT uq.timespan, COALESCE(tsq.TotalClicks, 0) as Clicks FROM (
SELECT DATE( DATE_ADD( NOW( ) , INTERVAL -21
DAY ) ) c, DATE( DATE_ADD( NOW( ) , INTERVAL -28
DAY ) ) l
union SELECT DATE( DATE_ADD( NOW( ) , INTERVAL -15
DAY ) ) c, DATE( DATE_ADD( NOW( ) , INTERVAL -20
DAY ) ) l
union SELECT DATE( DATE_ADD( NOW( ) , INTERVAL -8
DAY ) ) c, DATE( DATE_ADD( NOW( ) , INTERVAL -14
DAY ) ) l
union SELECT curdate() c,DATE( DATE_ADD( NOW( ) , INTERVAL -7
DAY ) ) l
)uq LEFT JOIN (
SELECT CASE
WHEN submitdate >= NOW() - INTERVAL 4 WEEK
AND submitdate < NOW() - INTERVAL 3 WEEK THEN c 'to' l
DAY ) )
WHEN submitdate >= NOW() - INTERVAL 3 WEEK
AND submitdate < NOW() - INTERVAL 2 WEEK THEN c 'to' l
WHEN submitdate >= NOW() - INTERVAL 2 WEEK
AND submitdate < NOW() - INTERVAL 1 WEEK THEN c 'to' l
DAY ) )
WHEN submitdate >= NOW() - INTERVAL 1 WEEK THEN c 'to' l
END Weeksubmitdate,
count(id) TotalClicks
FROM survey
WHERE submitdate >= NOW() - INTERVAL 4 WEEK
GROUP BY Weeksubmitdate
)tsq ON uq.timespan = tsq.Weeksubmitdate";
problem is with 16th line c to l.
I am getting the following error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''to' l
DAY ) )
WHEN submitdate >= NOW() - INTERVAL 3 WEEK
' at line 16
CASE is supposed to evaluate to a scalar expression. That means its THEN clauses must evaluate to scalar expressions too. Now, what does this c 'to' l thing stand for? Is it a scalar expression? It doesn't seem one to me, however I may be unaware of some things in MySQL, so it's more important whether MySQL itself recognises that as a scalar expression. And apparently it doesn't.
There is another issue. You are trying to reference a derived table's columns inside another derived table. More specifically, you seem to be trying to reference the columns c and l of uq inside the tsq subselect, and that is illegal. If uq was a normal table, it would be fine, but since it is a virtual table, the query doesn't know about its existence at that point, i.e. at the time of parsing the tsq subquery.
Anyway, what you seem to be doing with your query could probably be rewritten more simply, like this, for instance:
SELECT
MIN(submitdate) AS startdate,
MAX(submitdate) AS enddate,
COUNT(*) AS clicks
FROM (
SELECT
CASE
WHEN submitdate >= NOW() - INTERVAL 1 WEEK THEN 1
WHEN submitdate >= NOW() - INTERVAL 2 WEEK THEN 2
WHEN submitdate >= NOW() - INTERVAL 3 WEEK THEN 3
WHEN submitdate >= NOW() - INTERVAL 4 WEEK THEN 4
END AS weekid,
*
FROM survey
) s
GROUP BY
weekid
ORDER BY
startdate
;
The subquery assigns surrogate week IDs to every row of survey. The main query groups the results by those IDs and produces the counts as well as starting & ending dates for every group.
I have a table with: userid and timestamp each time a user opens a page a new field is inserted.
I am trying to get the total amount of hours / minutes / days / weeks that appear in a 1 month interval for multiple users.
I have tried a bunch of different queries but each have ended up terribly inefficient.
Ideally I'd like to end up with something like:
userid | minutes | hours | days | weeks
1 10080 168 7 1
2 1440 24 1 0
Hopefully someone can shed some light on how to do this.
Below is a query that I tried:
SELECT
w.time AS `week`,
d.time AS `day`,
h.time AS `hour`,
m.time AS `minutes`
FROM (
SELECT
SUM( t.time ) AS `time`
FROM (
SELECT
COUNT( DISTINCT WEEK( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY MONTH( `timestamp` )
) t
) w,
(
SELECT
SUM( t.time ) AS `time`
FROM (
SELECT
COUNT( DISTINCT DAY( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "52"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY MONTH( `timestamp` )
) t
) d,
(
SELECT
SUM( t.timestamp ) AS `time`
FROM (
SELECT
COUNT( DISTINCT HOUR( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY DAY( `timestamp` )
) t
) h,
(
SELECT
SUM( t.timestamp ) AS `time`
FROM (
SELECT
COUNT( DISTINCT MINUTE( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY HOUR( `timestamp` )
) t
) m
It seems awfully excessive for this task, maybe someone has something better?
It's not clear to me what you want to "total".
If you want to determine whether a user had a "hit" (or whatever transaction it is you are storing in the table) at any given minute within the month), and then you want to count the number of "minute periods" within a month that a user had a hit:
SELECT t.userid
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d %H:%i')) AS minutes
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d %H' )) AS hours
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d' )) AS days
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%X-%V' )) AS weeks
FROM mytable t
WHERE t.timestamp >= '2012-06-01'
AND t.timestamp < '2012=07-01'
GROUP BY t.userid
What this is doing is taking each timestamp, and putting it into a "bucket", by chopping off the seconds, chopping off the minutes, chopping off the time, etc.
Basically, we're taking a timestamp (e.g. '2012-07-25 23:15:30') and assigning it to
minute '2012-07-25 23:15'
hour '2012-07-25 23'
day '2012-07-25'
A timestamp of '2012-07-25 23:25:00' would get assigned to
minute '2012-07-25 23:25'
hour '2012-07-25 23'
day '2012-07-25'
Then we go through and count the number of distinct buckets we assigned a timestamp to. If that's all the hits for this user in the month, the query would return a 2 for minutes, and a 1 for all other period counts.
For a user with a single hit within the month, all the counts for that user will be a 1.
For a user that has all their "hits" within exactly the same minute, the query will again return a 1 for all the counts.
(For a user with no "hits" within a month, no row will be returned. (You'd need to join another row source to get a list of users, if you wanted to return zero counts.)
For a user with a "hit" every second within a single day, this query will return counts like that shown for userid 2 in your example.
This result set gives you a kind of an indication of a user's activity for a month... how many "minute periods" within a month the user was active.
The largest value that could be returned for "days" would be the number of days in the month. The largest possible value to be returned for "hours" would be 24 times the number of days in the month times. The largest possible value returned for "minutes" would be 1440 times the number of days in the month.
But again, it's not entirely clear to me what result set you want to return. But this seems like a much more reasonable result set than the one from the previously "selected" answer.
SELECT userid, SUM(MINUTE(timestamp)) AS minutes, SUM(MINUTE(timestamp))/60 AS hours, SUM(MINUTE(timestamp))/(60*24) AS days, SUM(MINUTE(timestamp))/(60*24*7) AS weeks
FROM Table
GROUP BY userid
If neccesary, use ROUND(SUM(MINUTE(timestamp)), 0) if you want integer numbers.