I'm trying to work with a database of unemployment figures from the department of labor statistics' data (available at ftp://ftp.bls.gov/pub/time.series/la/)
I need to get the last 12 months of data for any given state, which is trickier then just selecting all data from the last year as they don't always have the last few months of data in yet (right now, the last month's worth of data is November 2010).
I know which record is the newest, and the date fields I have in the database to work with are:
period_name (month name)
year
period (M01, M02, etc for January, February)
My current SQL, which pulls data from a bunch of JOINed tables, is:
USE unemploymentdata;
SELECT DISTINCT series.series_id, period_name, year, value, series.area_code,
footnote_codes, period_name, measure_text, area_text, area_type_text
FROM state_overview
LEFT JOIN series ON state_overview.series_id=series.series_id
LEFT JOIN footnote ON state_overview.footnote_codes = footnote.footnote_code
LEFT JOIN period ON state_overview.period = period.period
LEFT JOIN measure ON series.measure_code = measure.measure_code
LEFT JOIN area ON series.area_code=area.area_code
LEFT JOIN area_type ON area.area_type_code=area_type.area_type_code
WHERE area_text = 'State Name' AND year > 2009
ORDER BY state_overview.period, measure_text;
Any idea?
Since you have textual values to work with for month and year, you'll need to convert them to MySQL-formatted DATE values and can then let MySQL calculate the last year interval like so:
SELECT ... WHERE STR_TO_DATE(CONCAT(period_name,' 1 ',year),'%M %d %Y') >= DATE_SUB(STR_TO_DATE(CONCAT(most_recent_period_name,' 1 ',most_recent_year),'%M %d %Y'), INTERVAL 1 YEAR) ...;
The CONCAT() function is just building a string like "Month 1 YYYY", and the STR_TO_DATE() function is taking that string and a formatting string to tell it how to parse it, and converting it into a DATE.
Note: This query probably sucks index-wise but it should work. : )
I think a few changes to WHERE clause should do it, but for effeciency/simplcity you should also add MAX(year) to the SELECT section.
SELECT ...... MAX(year) as max_year .....
WHERE area_text = 'State Name'
AND year >= max_year - 1
AND period >= (SELECT MAX(period) WHERE year = max_year)
ORDER BY state_overview.period, measure_text;
You can store the year and month as a date, even though you don't have the day information. Just use the first of each month.
{2009, 'M1'} => 2009-01-01
{2009, 'M2'} => 2009-02-01
{2009, 'M3'} => 2009-03-01
This makes date arithmetic much easier than dealing with substrings of (potentially dirty) data. Plus (and this is big), you can index the data much more effective. As a bonus, you can now extract a lot of extra goodies using DATE_FORMAT such as month names, nr of days in month etc.
Does all states have data for all months, and is the data updated at the same time? The answer to that question dictates what query strategy you should use.
The best way is to take the strtotime ($a) of correct 1 year ago and then, when fetching the value from database then find the strtotime ($b) of the date in each result. Now
if($b < $a){
continue;
}
else {
//do something.
}
Related
I'm working on a task where I need to find the expected date to resolve a ticket using createdAt and sla_name fields values. After that I need to compare the this expected date with the dates in holidays table.
If the expected date falls in holidays, I need to extend the sla_name field value.
This is the query am using.
SELECT t.sla_meet, t.tid, t.ticket_id, t.ticket_name,t.createdAt,t.updatedAt,t.status, dw.dropdown_name
as ticket_priority,p.project_name, dw3.dropdown_name as ticket_status,t.sla as sla_name,
isn.issue_name as issue_type,inn.incidentName as incident_type,t.ticket_accepted_date,
t.asset_id,t.ticket_closed_date,t.contact_number,
IF(NOW() <= DATE_ADD(t.createdAt,INTERVAL (t.sla)+1 DAY),'YES','NO') AS slaMeetData
from tickets t
JOIN assets ast ON t.asset_id=ast.asset_id
JOIN projects p ON p.project_id=ast.project_id
JOIN admin_dropdowns dw ON t.ticket_priority=dw.id
JOIN admin_dropdowns dw3 ON t.ticket_status=dw3.id
JOIN issues isn ON t.issue_type=isn.issue_id
JOIN incident_names inn ON t.incident_type=inn.incidentId
order by t.tid DESC
This is the resultant data of the above query.
Now I need to compare the holidays in above query. And the sample data is,
If the expected date that am getting in IF condition of above query is falls in this holidays, I need to update the sla_name value with COUNT OF HOLIDAYS(If startdata and enddate are there, need to count the days between them) + sla_name.
If expected date is falls on dates range(start and end dates of holidays), need to calculate the count of days from expected date to end date and update that count in sla_name field
Is it possible to do this functionality in SQL? I've used the above query as VIEWS.
Instead of t.sla AS sla_name, use this expression to determine whether to add the length of the overlapping holiday to the number of days:
(
t.sla +
IF(
DATE_ADD(t.createdAt,INTERVAL (t.sla)+1 DAY) BETWEEN holidays.holiday_date AND holidays.end_date,
DATEDIFF( holidays.end_date, holidays.holiday_date ), /* add holiday length number of days */
0 /* no holiday overlap so don't add any days */
)
) as sla_name
You'll also have to join on the holidays table to find the holiday (if any) which overlaps the date in question:
JOIN holidays ON ( DATE_ADD(t.createdAt,INTERVAL (t.sla)+1 DAY) BETWEEN holidays.holiday_date and holidays.end_date )
SELECT * FROM table WHERE '2016-03-31' > (SELECT MAX(year) from table where bill_id = 'somevalue')
I am using above query to check if 2016-03-31 is greater than all years present in table against bill_id. It is working fine. but is it correct approach to compare dates. dates will always in above format. Is there any need to convert date format for comparison. value 2016-03-31 will change dynamically but it will be always in Y-m-d format
Note : year is column name which contains full date in Y-m-d format like 2016-05-20
You are not comparing dates. You are comparing a string '2016-03-31' with a number, e.g. 2015.
In order to compare, MySQL silently converts the string to number. One would expect this to crash, as '2016-03-31' certainly isn't a number. MySQL, however, reads from left to right and takes from there all that can be considered a number, i.e. '2016'. Well, one could argue that some people put a minus sign at the end of a number, so this should be '2016-', i.e. -2016. Anyway, MySQL stops before the minus sign, gets 2016 and uses this for the comparision.
I don't know if all this is guaranteed to work in the future. I would not rely on this.
What result would you expect anyway? Is the 31st of March 2016 greater than the year 2016? That's a queer question, don't you think?
Try this. But do you really have a column year that stores only year?
SELECT * FROM table WHERE year(STR_TO_DATE('2016-03-31'))
> (SELECT MAX(year) from table where bill_id = 'somevalue')
SELECT * FROM table WHERE YEAR('2016-03-31') > (SELECT MAX(year) from table where bill_id = 'somevalue')
MySQL YEAR() returns the year for a given date or timestamp. The return value is in the range of 1000 to 9999 or 0 for 'zero' date.
I have table having 26 columns in which first 3 Columns are day,month,year. And rest of columns having some information that i have to show. Now i have to fetch records according to month's last day.
I have tried writing code.
select * from subscription_stats where year * 10000 + month * 100 + day = LAST_DAY(CONCAT(year,'-',month,'-',day))
But this will fetch records from last day of every month. When i dont have actual last day in records then this code will not work. So instead of LAST_DAY i want some functionality like MAX date in that month. How can i implement this functionality.
You want the last date in each month in your data. For this:
select s.*
from subscription_stats s
where s.day = (select max(s2.day)
from subscription_stats s2
where s2.year = s.year and s2.month = s.month
);
Although it would not make this query much simpler, you should be storing dates as dates in your table. That is, one date, not three separate columns for year/month/day.
I have attendance data for employees stored in the table attendance with the following column names:
emp_id (employee ID)
date
type (leave, absent, etc.)
(there are others but I'm omitting them for the sake of simplicity)
My objective is to retrieve all dates of the given month on which the employee was on leave (type = 'Leave') and the last leave taken in the last month, if any.
It's easy to do it using two queries (I'm using PHP to get process the data), but is there any way this can be done in a single query?
I'm answering my own question so as to close it. As #bpgergo pointed out in the comments, UNION will do the trick here.
SELECT * FROM table_name
WHERE type="Leave" AND
date <= (CURRENT_DATE() - 30)
Select the fields, etc you want then se a combined where clause using mysql's CURRENT_DATE() function. I subtracted 30 for 30 days in a month.
If date is a date column, this will return everyone who left 1 month or longer ago.
Edit:
If you want a specific date, change the 2nd month like this:
date <= (date_number - 30)
I have a Mysql Table that holds dates that are booked (for certain holiday properties).
Example...
Table "listing_availability"
Rows...
availability_date (this shows the date format 2013-04-20 etc)
availability_bookable (This can be yes/no. "Yes" = the booking changeover day and it is "available". "No" means the property is booked for those dates)
All the other dates in the year (apart from the ones with "No") are available to be booked. These dates are not in the database, only the booked dates.
My question is...
I have to make a SQL Statement that first calls the Get Date Function (not sure if this is correct terminology)
Then removes the dates from "availability_date" WHERE "availability_bookable" = "No"
This will give me the dates that are available for bookings, for the year, for a property.
Can anyone help?
Regards M
Seems like you've almost written the query.
SELECT availability_date FROM listing_availability
WHERE availability_bookable <> 'NO'
AND availability_date >= CURDATE()
AND YEAR(CURDATE()) = YEAR(availability_date)
I think I understand, and you'll obviously confirm. Your "availability_booking" has some records in it, but not every single day of the year, only those that may have had something, and not all are committed, some could have yes, some no.
So, you want to simulate All dates within a given date range... Say April 1 - July 1 as someone is looking to book a party within that time period. Instead of pre-filling your production table, you can't say that April 27th is open and available... since no such record exists.
To SIMULATE a calendar of days for a date range, you can do it using MySQL variables and join to "any" table in your database provided it has enough records to SIMULATE the date range you want...
select
#myDate := DATE_ADD( #myDate, INTERVAL 1 DAY ) as DatesForAvailabilityCheck
from
( select #myDate := '2013-03-31' ) as SQLVars,
AnyTableThatHasEnoughRows
limit
120;
This will just give you a list of dates starting with April 1, 2013 (the original #myDate is 1 day before the start date since the field selection adds 1 day to it to get to April 1, then continues... for a limit of 120 days (or whatever you are looking for range based -- 30days, 60, 90, 22, whatever). The "AnyTableThatHasEnoughRows" could actually be your "availability_booking" table, but we are just using it as a table with rows, no join or where condition, just enough to get ... 120 records.
Now, we can use this to join to whatever table you want and apply your condition. You just created a full calendar of days to compare against. Your final query may be different, but this should get it most of the way for you.
select
JustDates.DatesForAvailabilityCheck,
from
( select
#myDate := DATE_ADD( #myDate, INTERVAL 1 DAY ) as DatesForAvailabilityCheck
from
( select #myDate := '2013-03-31' ) as SQLVars,
listing_availability
limit
120 ) JustDates
LEFT JOIN availability_bookable
on JustDates.DatesForAvailabilityCheck = availability_bookable.availability_date
where
availability_bookable.availability_date IS NULL
OR availability_bookable.availability_bookable = "Yes"
So the above uses the sample calendar and looks to the availability. If no such matching date exists (via the IS NULL), then you want it meaning there is no conflict. However, if there IS a record in the table, you only want those where YES, you CAN book it, the entry on file might not be committed and CAN be in your result query of available dates.