I've got a terrible database on a project and they've used a text field for dates.
So, I need to build a view that has only the year in one column. The problem is that I have dates with any standard format like:
01-01-2012
01.01.2012
01 01 2012
1/1/2012
01/2012
1/2012
2012
01.2012
Is there any way to build an SQL (MySQL) to get only those 4 year digits to build a view?
Thanks a lot for your help!
It really depends on the whole data structure, you can use REGEX or String functions.
For example, with your sample data the last 4 digits on the right are the year so using
SELECT RIGHT(fieldname, 4) FROM table
would work. If that pattern doesn't work then you've either got to use concat and start splitting them or write a REGEX statement.
If RIGHT will work then you can do an INSERT SELECT
INSERT INTO table (yearcolumn)
SELECT RIGHT(fieldname, 4) FROM table
You can use REGEXP matching, to get rows from given year. There's no way to get a capture from regular expression though.
However, if the year part is alwayst last 4 digits, use RIGHT(). Otherwise, you will need to do reformatting client-side.
This may also help. This is Oracle query for the whole current year. It can be easily converted to any SQL. It uses recursive query to build annual table. Replace SYSDATE and Oracle formats with your version of SQL formats and system date:
WITH data(r, start_date) AS
(
SELECT 1 r, TRUNC(SYSDATE, 'YEAR') start_date FROM dual -- start_date: 1/1/2013
UNION ALL
SELECT r+1, TRUNC(SYSDATE, 'YEAR')+r-1 FROM data WHERE r < 365 -- any number: end_date - start_date or get the number of days in your year your way...
)
SELECT start_date
, TO_CHAR(start_date, 'YYYY') curr_year
, TRUNC(start_date, 'IW') wk_starts
, TRUNC(start_date, 'IW') + 7 - 1/86400 wk_ends
, TO_NUMBER (TO_CHAR (start_date, 'IW')) ISO_wk#
FROM data
/
START_DATE CURR_YEAR WK_STARTS WK_ENDS ISO_WK#
-----------------------------------------------------------------------
1/1/2013 2013 12/31/2012 1/6/2013 11:59:59 PM 1
1/1/2013 2013 12/31/2012 1/6/2013 11:59:59 PM 1
...
12/28/2013 2013 12/23/2013 12/29/2013 11:59:59 PM 52
12/29/2013 2013 12/23/2013 12/29/2013 11:59:59 PM 52
12/30/2013 2013 12/30/2013 1/5/2014 11:59:59 PM 1
Related
The column has a start and end date
month_name
23 March, 2018 - 23 April, 2018
23 March, 2018 is the start date and 23 April, 2018 is the end date
How can I use them as to the start date and end date to query?
You would need to use SUBSTRING_INDEX to return a part of the string to the left or right of the hyphen. But this would be terrible in terms of performance. So you need to look at your data structure and redesign accordingly. The start and end dates should be in distinct columns with an INDEX and appropriate DATATYPE set (DATETIME, TIMESTAMP, DATE).
I would suggest that you process the text prior to saving to the database, by using client language regex or split/substring functionality to correctly format the dates into MYSQL format before saving.
set #fromto='23 March, 2018 - 23 April, 2018';
select
str_to_date(left(#fromto,locate('-',#fromto)-1),'%d %M,%Y') datefrom,
str_to_date(right(#fromto,length(#fromto)-locate('-',#fromto)),'%d %M,%Y') dateto;
output:
+------------+------------+
| datefrom | dateto |
+------------+------------+
| 2018-03-23 | 2018-04-23 |
+------------+------------+
short explanation:
set #fromto - defines a variable, which is used as input for this example
locate('-',#fromto) - this will find the length of the part in #fromto before the '-', the -1 is needed because where only want the part before the '-'
length(#fromto)-locate('-',#fromto) - this will find the length of the part in #fromto after the '-'
str_to_date(...) - see STR_TO_DATE
For each and every query that would need to use these dates, you would have to unpick one or both of these dates that are relevant to the query using this kind of text and date manipulation
SELECT .....
WHERE whatever_else
AND STR_TO_DATE(SUBSTRING_INDEX(monthname, ' -', 1 ), '%d %M,%Y') = '2018-03-23'
AND STR_TO_DATE(SUBSTRING(monthname, INSTR(monthname, '- ') +2 ), '%d %M,%Y') = '2018-04-23'
In short your queries would be a complete nightmare to write and maintain and any indexing benefits you might have been able to use had these 2 dates been saved in 2 seperate columns are completely lost.
SUBSTRING_INDEX()
SUBSTRING()
INSTR()
STR_TO_DATE()
I have the scenario where I need to load data for next quarter ,this data should be insert only and from next day
data should be incremental load.For example for quarter 1 jan to 6 march .On 1 jan we have loaded historical load or first time insert and on 2 jan onwards it in incremental load. Now on 7 march we want fresh insert and from 8 march incremental load will run on newly insert data on 7 march. Like we want to lock the data from the quarter 1 jan to 6 march and fresh insert should happen on 7 march and 8 march incremental load should run on data loaded on 7 march. How to achieve this in ssis?
The best way to do this is create a calendar table and have a special column within that table that maps every single date to a 'freeze date' attribute.
So I leave you to do some research on calendar tables.
In the meantime, without a calendar table, here is something to get you started.
Firstly, this expression gives you the first month in the current quarter. So if today is anywhere within Jan - Mar, this expression gives you 1. If today is anywhere within Oct-Dec, it gives you 10
SELECT (((MONTH(GETDATE()))-1)/3)*3+1 As FirstMonthInCurrentQuarter
Now we convert that number to an actual date on the first of the month.
First, generate a numeric representation:
SELECT
YEAR(GETDATE()) * 10000 +
((((MONTH(GETDATE()))-1)/3)*3+1) * 100 +
1
We just convert that to an actual date:
SELECT
CONVERT(
DATE,
CAST(
YEAR(GETDATE()) * 10000 +
((((MONTH(GETDATE()))-1)/3)*3+1) * 100 +
1
AS VARCHAR(8)),
112)
That's a monstrous expression that can be replaced with a calendar table.
If you run it right now you'll get 1 Jan 2019. If you run that on 5th April you'll get 1st April. Hopefully you understand how that shuffles along automatically.
Now we use that date to decide what to load into your table.
DECLARE #LoadDate DATE
SET #LoadDate =
CONVERT(
DATE,
CAST(
YEAR(GETDATE()) * 10000 +
((((MONTH(GETDATE()))-1)/3)*3+1) * 100 +
1
AS VARCHAR(8)),
112)
-- Delete all the data in the target table after this date:
DELETE TargetTable WHERE TransactionDate >= #LoadDate;
-- Use your ETL tool to load this in:
INSERT INTO TargetTable (TransactionDate, Amount, Account)
SELECT TransactionDate, Amount, Account
FROM SourceTable WHERE TransactionDate >= #LoadDate;
You have nowhere near enough information in your question for a meaningful answer, but maybe this will give you an idea
95% chance you never return though.
Need to track and bill delivers based on date, for example if a deliver came in After 01/18/2010 but before 02/11/2010 it would be billed to Job no. 198.
I pretty much know it would be:
SELECT `no` FROM `jobs` WHERE 'start_date' >'2010-01-18' AND <`2010-02-11`;
in order to get '2010-01-18' AND < '2010-02-11', I have to look in the data base of course that defeats the purpose
I am given the Var=$delivery_date
And I am stuck right here.
How can I get the between dates without looking each time.
Sample of data base
no Start Date
198 2010 01 18 14:35
199 2010 02 11 12:10
200 2010 03 07 12:33
201 2010 03 31 17:35
202 2010 05 25 05:05
203 2010 06 20 01:05
204 2010 07 14 08:50
205 2010 07 21 11:31
206 2010 09 07 03:47
I hope I explained it well enough. I look at the manual and other questions but it always seems like they only have one date that is a variable and all of mine are
PS changing the format or method of the tables is not an option unless you can point me towards the time travel section
You can use the following select statement:
SELECT * FROM jobs WHERE date(start_date) BETWEEN "2010-02-08" AND "2010-03-15";
so you only take the date portion into account, not the time.
so with your date format it would be something like
SELECT * FROM jobs WHERE date(STR_TO_DATE(start_date, '%Y %m %d %h:%i')) BETWEEN "2010-02-08" AND "2010-03-15"
Looks like you want to find a jobs record with the largest start_date that's also less than $delivery_date. Here's the query
SELECT no
FROM jobs
WHERE `start_date` < $delivery_date
ORDER BY `start_date` DESC LIMIT 1
If $delivery_date is set to 2010-02-08, the above query will return 198 like you expected.
If $delivery_date is set to 2010-03-15, the above query will return 200.
thanks to ekad this worked perfectly
SELECT no
FROM jobs
WHERE start_date < $delivery_date
ORDER BY start_date DESC LIMIT 1
after the query the job no i need is first one
I am using VB and MySQL. I have a field named xTime and the data type is TIME. I am trying to find a way to order it ASC or enable it to have the PM/AM in it. Right now my Data is as follows and I need the 3:20 and 5:50 to be after since those should be pm. Any ideas?
62 4 3 03:20:00
61 4 3 05:50:00
56 1 1 07:40:00
Here is my SQL Statement:
SELECT ReserveID, MembershipID, Player_Count, `Time`, CourseID, `Date`
FROM reserve
WHERE (CourseID = 1) AND (`Date` = CURDATE())
ORDER BY `Time`
Actually, your code and your data seem to be fine. Your code is ordering by time ascendingly and your results are displaying it the way they should. The issue is that you're interpreting the data in the wrong way:
I need the 3:20 and 5:50 to be after since those should be pm
3:20 and 5:50 must be before 7:40 always, because those are all AM times. 3:20 PM is equal to 15:20 and 5:50 PM is equal to 17:40.
I have some orders in a table and the last order date of 2011 is 20th Dec.
I'm using a sql command to calculate the number of orders in a given week:
SELECT CONVERT(VARCHAR(3),DATENAME(week,convert(datetime,order_date,103))) AS week,
COUNT(1) as orders
FROM order_table
where DATENAME(YEAR,convert(datetime,order_date,103)) = '2011'
GROUP BY CONVERT(VARCHAR(3),DATENAME(week,convert(datetime,order_date,103)))
order by week asc
It returns me the some of the following results:
Week | Orders
41 | 42
42 | 110
43 | 115
...
...
51 | 155
52 | 15
The trouble with this is is that the last order date of 2011 as mentioned that I have is 20th Dec 2011, which can't be week 52 so must be week 51.
I've got some other stats(off another system, not SQL server) which giving me some other figures and the last week on it is 51 which I have no doubt is correct. So there's going to be a queries if people are looking both!
Anyone have any idea or know how to sort this?
Thanks,
The iso_week of 20th Dec 2011 is 51. So maybe that is what you need.
SELECT datepart(iso_week, '2011-12-20')
SQL Counts a week as Sunday-Saturday, you can use the script below to see how the weeks break out for 2011. The 1st of January is a Saturday, which means the first week is only 1 day. There are 53 SQL weeks in 2011, and 53 weeks in most years
DECLARE #dStartDate DATETIME
SET #dStartDate = '01/01/2011'
WHILE #dStartDate < '01/01/2012'
BEGIN
PRINT CONVERT(VARCHAR, #dStartDate, 101)
+ ' : '
+ CONVERT(VARCHAR, DATEPART(WEEK, #dStartDate))
+ ' : '
+ DATENAME(DW, #dStartDate)
SET #dStartDate = #dStartDate + 1
END
If you want to change the day SQL counts as the first of the week, you can use the DATEFIRST command
http://msdn.microsoft.com/en-us/library/ms181598.aspx
SELECT DatePart(WEEK,order_date) AS WeekOfYear
FROM order_table
Should give you the week number.
So do
Select * from order_table Where DatePart(Week, order_date) = 52
See what is week 52 not what you think is 52.
PS Given you are starting week 1 on the 1/1 it's not possible to have a 52 week year, unless 1 and or 52 are not seven day weeks.