I have a datatable with year and month columns. I store these values as number, like 2014 and 1 for jan 2014, etc.
Now, I would like to select all values between 2014-01 and f. e. 2015-5.
I have tried it different ways (between the two values, concating them), but it exists always values, which the result set don't contains.
How should be look the query?
How about the following:
SELECT * FROM MyTable m
WHERE CDate(m.month & "/1/" & m.year) Between #1/1/2014# AND #5/1/2015#
It appears you want:
All data from 2014
2015 data from Jan through May
If that's correct, you can ask Access to give you those data directly ... without the need to first transform your year and month fields to a date value.
SELECT *
FROM datatable
WHERE
year_field = 2014
OR
(
year_field = 2015 AND month_field <= 5
);
With year_field and month_field indexed, this query should be much faster than an alternative where you apply CDate or Format to every row of the table and thereby forego any opportunity to benefit from indexed retrieval.
On the other hand, if your table is small enough, you probably wouldn't notice the horrible inefficiency. :-)
You are not defining your RBDMS, so I'm supposing you use ORACLE, you can change the syntax of course.
SELECT *
FROM [table]
WHERE (SELECT to_date(to_char(year) || '/' || to_char(month) || '/01', 'yyyy/mm/dd')
FROM dual)
BETWEEN (SELECT to_date('year/mm/01', 'yyyy/mm/dd' FROM dual)
AND (SELECT to_date('year2/mm2/01', 'yyyy/mm/dd' FROM dual)
Untested.
Notice you need to replace year and mm for the beginning date and year2 and mm2 for the ending date.
I got yelled at one time because between is not safe apparently, so you may prefer
SELECT *
FROM MYTABLE AS m
WHERE Format(m.month & "/1/" & m.year,"mm/dd/yyyy") >=
Format(#1/1/2014#,"mm/dd/yyyy") AND
Format(m.month & "/1/" & m.year,"mm/dd/yyyy") <=
Format(#5/1/2015#,"mm/dd/yyyy")
Also base code stolen from Linger
You should convert the two parts of all of the involved parameters into actual dates and use BETWEEN on them instead.
SELECT [field_list]
FROM [table_name] t
WHERE CDate(t.year + '/' + t.month + '/02')
BETWEEN #2014/01/01#
AND #2014/05/03#;
If you have an actual day field you can use that, but for simplicity, and assuming you aren't using the day, the above setup should work fine for you.
Related
I´m looking for a solution, where I can select the entries between 2 dates. My table is like this
ID | YEAR | MONTH | ....
Now i want to SELECT all entries between
MONTH 9 | YEAR 2015
MONTH 1 | YEAR 2016
I don´t get any entries, because the 2nd month is lower than the 1st month. Here is my query:
SELECT *
FROM table
WHERE YEAR >= '$year'
AND MONTH >= '$month'
AND YEAR <= '$year2'
AND MONTH <= '$month2'
I can´t change the columns of the table, because a csv import is like this. Can anyone help me on this?
The years aren't disconnected from the months, so you can't test them separately.
Try something like
$date1 = $year*100+$month; // will be 201509
$date2 = $year2*100+$month2; // will be 201602
...
SELECT * FROM table WHERE (YEAR*100)+MONTH >= '$date1' AND (YEAR*100)+MONTH <= '$date2'
Make sure you protect against SQL injection though.
SELECT
*
FROM
`my_table`
WHERE
((`YEAR` * 12) + `MONTH`) >= (($year * 12) + $month)
AND ((`YEAR` * 12) + `MONTH`) <= (($year2 * 12) + $month2)
Since they aren't date fields, you need to convert to numbers that can be compared against. Multiplying the year by 12 and adding the month will give you a unique number specific to that month of the year. Then you can compare on that.
There are a couple of good answers, but assuming taht you don't/can't change the date's format something you can do is
WHERE ((YEAR>'$year') OR
(YEAR=='$year' AND MONTH>='$month')
AND ((YEAR<'$year2') OR
(YEAR=='$year2' AND MONTH<='$month2')
I would suggest the workarounds though (like alphabetically comparing in YYYYMM[DD] format).
You need to pad the month to make sure it starts with a zero. Otherwise 20162 will be lower than 201512, for example.
$date1 = $year . str_pad($month, 2, "0", STR_PAD_LEFT);
$date2 = $year2 . str_pad($month2, 2, "0", STR_PAD_LEFT);
"SELECT * FROM dates WHERE concat(`year`, LPAD(`month`, 2, '0')) >= '$date1' AND concat(`year`, LPAD(`month`, 2, '0')) <= '$date2'"
Though there are a lot of ways to solve this problem, but the best way is to convert these values into a proper date type in mysql query using str_to_date it is PHP's equivalent of strtotime, your new query should look like this
SELECT
d.*
from
dates as d
where
STR_TO_DATE( concat('1,',d.month,',',d.year) ,'%d,%m,%Y') > STR_TO_DATE('1,5,2015','%d,%m,%Y')
and
STR_TO_DATE( concat('1,',d.month,',',d.year) ,'%d,%m,%Y') < STR_TO_DATE('1,4,2016','%d,%m,%Y')
Using this technique you can easily compare dates and do much more and not worry about other complexities of calendars.
Source: MySQL date and time functions
I'm trying to track down new id numbers over time for at least the past twelve months. Note, the data is such that once id numbers are in, they stick around for at least 3-5 years. And I just literally run this thing once a month. These are the specs, Oracle Database 11g Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production.
So far I'm wondering if I can use more dynamic date ranges and run this whole thing on a timer, or if this is the best way to write something. I've just picked up sql mostly through Googling and looking at sample queries that others have graciously shared. I also do not know how to write PL/SQL right now either but am willing to learn.
create table New_ids_calendar_year_20xx
as
select b.id_num, (bunch of other fields)
from (select * from source_table where date = last_day(date_add(sysdate,-11))a, (select * from source_table where date = last_day(date_add(sysdate,-10))b where a.id_num (+) = b.id_num
union all
*repeats this same select statement /w union all until:
last_day(date_add(sysdate,0)
In Oracle there is no built-in function date_add, maybe you have some which you created, anyway for adding and substracting dates
I used simple sysdate+number. Also I am not quite sure about logic behind your whole query. And for field names - better avoid
reserved words like date in column names, so I used
tdate here.
This query does what your unioned query did for last 30 days. For other periods change 30 to something other.
The whole solution is based on the hierarchical
subquery connect by which gives simple list of numbers 0..29.
select b.id_num, b.field1 field1_b, a.field1 field1_a --..., (bunch of other fields)
from (select level - 1 lvl from dual connect by level <= 30) l
join source_table b
on b.tdate = last_day(trunc(sysdate) - l.lvl - 1)
left join source_table a
on a.id_num = b.id_num and a.tdate = last_day(trunc(sysdate) - l.lvl)
order by lvl desc
For date column you may want to use trunc(tdate) if you store time also, but this way your index on date field will not work if one exists.
In this case change date condition to something like x-1 <= date and date < x.
Sorry for the vague Problem statement, maybe I could not frame it the right way hence couldn't get much help from the internet.
My basic intent is to select two columns from a table, where the table has been partitioned based on dates, and has huge number of records.
The intent is to select records for each date from jan 1 to nov 30, can't do it using date between statement, I need to input each date separately in the iteration in for loop.
Can anyone help writing a dummy sql query on this?
Thanks,
you can use any scripting language to iterate over each day to achieve.
below is a sample (untested code)
import pyodbc
conn = pyodbc.connect(DSN='dsnname',autocommit=True,ansi=True)
cur = conn.cursor()
sql = "INSERT INTO tgt_table SELECT col1,col2 FROM src_table WHERE partitioned_date_column = date '2014-01-01' + INTERVAL '%d' DAY"
for i in range(1,30):
cur.execute(sql % i)
Assuming you use oracle, this dummy select should give you the list of dates to join
select to_date('01.01.2014','dd.mm.yyyy') + level - 1
from dual
connect by level -1 <= to_date('30.11.2014','dd.mm.yyyy') - to_date('01.01.2014','dd.mm.yyyy')
I dont know how your tables look like, but have you tryed something like this:
"WHERE {yourRow} > X GROUP BY date"
MySQL Query GROUP BY day / month / year
Hope this can help you :-)
SELECT col1, col2 FROM {table} WHERE datecol between '2000-01-01'
and
DATE_ADD('2000-01-31',INTERVAL 1 DAY)
OR
SELECT col1, col2, FROM {table} GROUP BY DAY(datecol)
I have a table on sql server (SSMS) with a column that contains 4-digit codes. Say 0713 stands for July 2013, and 0114 stands for Jan 2014. Now I want to convert the former to the latter, I wonder what can be the most efficient sql query to convert?
Thanks for any advice!
Probably the most efficient way is a case statement:
select (case left(col, 2)
when '01' then 'January '
when '02' then 'Feburary '
. . .
when '12' then 'December '
end) + right(col, 2)
This has the fewest calls to functions. There are more concise ways to do this, such as:
select datename(month, cast('2013' + col as datetime)) + right(col, 2)
Of course, to get the most efficient, you should set up a test in your environment on something like 1 million records and actually test the different timings.
For instance, it might be fastest to have a reference table with 366 entries, one for each day, and use a join to do the conversion.
On your final format it looks like you are wavering between values (Jan for January, but the full month name for July, instead of Jul). In that case, a look up table for the formatted months and a query to it.
Your FormattedMonth table could contain MonthName (the string you want to use) and MonthNumber (this would be most efficient as an int)
For Example:
SELECT originaldates.identifier, FormattedMonth.MonthName + ' 20' + originaldates.year
FROM (Select identifier, left(shortdate,2) as month, right(shortdate,2) as year
from Tablecontainingfield) originaldates
JOIN FormattedMonth
ON cast(FormattedMonth.MonthNumber as int) = originaldates.month
How best store year, month, and day in a MySQL database so that it would be easily retrieved by year, by year-month, by year-month-day combinations?
Let's say you have a table tbl with a column d of type DATE.
All records in 1997:
SELECT * FROM tbl WHERE YEAR(d) = 1997
SELECT * FROM tbl WHERE d BETWEEN '1997-01-01' AND '1997-12-31'
All records in March of 1997:
SELECT * FROM tbl WHERE YEAR(d) = 1997 AND MONTH(d) = 3
SELECT * FROM tbl WHERE d BETWEEN '1997-03-01' AND '1997-03-31'
All records on March 10, 1997:
SELECT * FROM tbl WHERE d = '1997-03-10'
Unless a time will ever be involved, use the DATE data type. You can use functions from there to select portions of the date.
I'd recommend the obvious: use a DATE.
It stores year-month-day with no time (hour-minutes-seconds-etc) component.
Store as date and use built in functions:day(), month() or year() to return the combination you wish.
What's wrong with DATE? As long as you need Y, Y-M, or Y-M-D searches, they should be indexable. The problem with DATE would be if you want all December records across several years, for instance.
This may be related to the problem that archivists have with common date datatypes. Often, you want to be able to encode just the year, or just the year and the month, depending on what information is available, but you want to be able to encode this information in just one datatype. This is a problem which doesn't apply in very many other situations. (In answer to this question in the past, I've had techie types dismiss it as a problem with the data: your data is faulty!)
e.g., in a composer catalogue you are recording the fact that the composer dated a manuscript "January 1951". What can you put in a MySQL DATE field to represent this? "1951-01"? "1951-01-00"? Neither is really valid. Normally you end up encoding years, months and days in separate fields and then having to implement the semantics at application level. This is far from ideal.
If you're doing analytics against a fixed range of dates consider using a date dimension (fancy name for table) and use a foreign key into the date dimension. Check out this link:
http://www.ipcdesigns.com/dim_date/
If you use this date dimension consider how easily it will be to construct queries against any kind of dates you can think of.
SELECT * FROM my_table
JOIN DATE_DIM date on date.PK = my_table.date_FK
WHERE date.day = 30 AND
date.month = 1 AND
date.year = 2010
Or
SELECT * FROM my_table
JOIN DATE_DIM date on date.PK = my_table.date_FK
WHERE date.day_of_week = 1 AND
date.month = 1 AND
date.year = 2010
Or
SELECT *, date.day_of_week_name FROM my_table
JOIN DATE_DIM date on date.PK = my_table.date_FK
WHERE date.is_US_civil_holiday = 1