We're using SQL Server 2005 and wanted to append two integers into another one. Right now we're summing the month and year of a date field, which isn't really what we want. Instead, we'd like to append them together, but retain an integer.
Here's what we have right now:
SELECT
YEAR( MeetingDate) + MONTH( MeetingDate) AS DateGroup
We'd like DateGroup to read 20118, 20119, 201110, 201111 etc. Trying to learn some good ways of doing this.
Consider using a leading zero for one digit months, i.e. 201108 rather than 20118, then it's easy:
select
year(MeetingDate) * 100 + month(MeetingDate) as DateGroup
Otherwise you have to treat some months differently:
select
year(MeetingDate) * case when month(MeetingDate) < 10 then 10 else 100 end
+ month(MeetingDate) as DateGroup
Cast your integers to varchar and then add them togehter.
select cast(cast(year(MeetingDate) as varchar(4)) +
cast(month(MeetingDate) as varchar(2)) as int) as dategroup
Related
I am merging 2 huge tables in Snowflake and I have 2 columns (one on each table):
"Year_birth" and "Exam_date" and the info inside looks like this respectively:
"1918" and "2007-03-13" (NUMBER(38,0) and VARCHAR(256))
I only want to merge the rows where the difference (i.e., age when the exam was made) is ">18" and "<60"
I was playing around with SELECT DATEDIFF(year,Exam_date, Year_birth) with no success.
Any ideas on how would I do it in Snowflake?
Cheers!
You only have a year, so there is not much you can do about the specific day of the year -- you need to deal with approximations.
So, extract the year from the date string (arggh! it should really be a date) and just compare them:
where (left(datestr, 4)::int - yearnum) not between 18 and 60
I would strongly advise you to fix the database and store these values using a proper date datatype.
You will need to convert the integer year into a date before doing a datediff
example:
set YearOfBirth = 1918;
set ExamDate = '2007-03-03'::DATE;
-- select $YearofBirth as YearofBirth, $ExamDate as ExamDate;
select $YearofBirth as YearofBirth,($YearofBirth::TEXT||'-01-01')::DATE as YearofBirthDate, $ExamDate as ExamDate, datediff(year,($YearofBirth::TEXT||'-01-01')::DATE,$ExamDate) as YearsSinceExam;
USE YEARS_DIFF IN WHERE CLAUSE TO FILTER DIFFERENCE BETWEEN 18 & 60
SELECT DATEDIFF( YEAR,'2007-03-03',TO_DATE(2018::CHAR(4),'YYYY')) YEARS_DIFF;
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 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.
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
I am trying to figure out how to be able to select records based on even or uneven dates.
I have a table with 4 columns and one has the sign up date and I would like to segment them into two groups based on their sign up dates (using the day as the denominator). So 12/4/2013 would be in the even and 4/3/2012 in the uneven.
I am not sure how to construct this query, I was looking at the datepart but wasn't sure if there is something more straight forward.
thanks
SELECT signed_on, DAY(signed_on) % 2 AS uneven
FROM YourTable
uneven will be either 0 or 1
SELECT DAY('2013-01-03') % 2 -- 1
SELECT DAY('2013-01-02') % 2 -- 0
If you want to name your column even rather than uneven you could just inverse the result.
SELECT signed_on, POWER(DAY(signed_on) % 2 - 1, 2) AS even
FROM YourTable
HINT (for now unless you can show you've tried something yourself) You could do something like DATEPART(day, date) % 2 with a case statement (case statement isn't necessary, but could be if you want to easily go between even and uneven without changing the query of course depending on your environment).
DATEPART(dd, your_date) should give you the date part of your date and then use % to find if it is even or not in the WHERE clause.
I believe something like this should be straight forward -
SELECT COL,CASE WHEN DAY(COL)%2=0 THEN 'EVEN' ELSE 'UNEVEN' END AS [EVEN_UNEVEN]
FROM TEST
Sample output from my sample table-
COL EVEN_UNEVEN
2014-01-09 22:39:51.203 UNEVEN
2014-01-10 22:39:51.210 EVEN
2014-01-12 22:39:51.210 EVEN
2014-01-13 22:39:51.213 UNEVEN