how to search for a date row in sql? - sql

I create column in this way:
ALTER TABLE cages
ADD test date;
I add date to this column
for instance
'01/07/21'
and when I use like always select:
select *
from cages
where test = '01/07/21';
I get nothing, it's weird, because in different table it's works... Can it connection with pk or fk or what is the reason of this?
edit:
I use SQL orlace developer.
edit:
thanks everyone for help, problem was that I used calendar to put date to column and it add date with time.
Why is it possible, when I have type date not dateTime?

Not everyone formats date values the same way. When looking at a date like 01/07/21, most of the people on this site will naturally read January 7, 2021*. The group that reads this as July 1, 2021 (today) is significant, but still slightly smaller. A few people come from cultures where July 21, 2001 is the natural interpretation.
To avoid this kind of ambiguity, when writing date literals for SQL you should always format them using the ISO-8601 formats, which always uses four digit years, goes in sequence from most significant term on the left to least significant term on the right, and always uses leading zeroes to fill out the full width of a term:
yyyy-MM-dd HH:mm:ss.fff
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd
yyyyMMdd (unseparated version of the format preferred on Sql Server for date-only values for historical reasons)
Anything else is wrong for SQL.
For completeness, I also want to key in on the word "literals" from the beginning of the second paragraph. We should always use parameterized queries/prepared statements when putting date values into a query from a client code language, rather than using string manipulation to substitute a literal into the SQL command. On strongly typed platforms this usually means using the DateTime type provided by the language to set the value. If you find yourself converting a datetime variable to a string for inclusion in an SQL query, you're making a mistake.
* This isn't just a blind assertion. A few years back I did a basic review of the public portion of the Stack Overflow developer survey, where I first looked up which countries/languages default to which date formats, and then grouped countries together based on their format. I wish I had saved the results :/. I forget how I treated places with mixed heritage like Canada.

Your root problem, and I'm amazed no one seems to have picked up on this, is that your column is a DATE but in your query you are comparing it to a STRING. This may or may not work, depending on your NLS_DATE_FORMAT setting. You need to compare like data types:
select *
from cages
where test = to_date('01/07/21','dd-mm-yy');
I leave it as an exercise for the student to go to the SQL Reference manual and read up on the TO_DATE function.
I also beg and plead with you to not be trying to use 2-digit years. As an industry we were supposed to have solved that problem over 20 years ago. Does the term "Y2k bug" not mean anything to you?
As it is, the date that is represented by the string '01/07/21' could be understood to be any of the following
Jan 7
Jan 21
Jul 1
Jul 21
And who knows the year? 2021? 1921? 1821? 2001? 1901? 2007? 1907?, 1807?
You might want to read this.

Using SQL Developer if you insert a date in a table using user interface it automatically generates hours and minutes like if it's a Timestamp. If the format you are using is correct you should be able to retrieve your rows using like operator instead of equal.
select * from cages where test like '01/07/21%';
The only way to retrieve your rows using equal operator is when the timestamp is set to 00:00:00

1st July 2021 is written date '2021-07-01' in Oracle SQL.
You can read more about literals in the Oracle SQL Reference.
You can also use a to_date expression like
to_date('2021-07-21','YYYY-MM-DD')
or
to_date('1-Jul-21', 'DD-Mon-YY', 'nls_date_language = English')
or indeed
to_date('1-Lug-21', 'DD-Mon-YY', 'nls_date_language = Italian')
but frankly, why would you?
Bear in mind that that the person running the query/report/procedure, or the application server in use, may not have the same territory and language settings as you, so it is dangerous to assume that the century for a 2-digit year will always be what you expect (what year is '50'?) or the language will always be English, or the week always starts on a Monday. I worked on a system once where we deployed some code that used 'DD-MON-YYYY', to offices in London and Paris. We deployed it in September, and we had a production issue in Paris in February, because Sep, Oct, Nov, Dec and Jan still worked, but French has no Feb.

Related

SQL Server Not Casting String YYYYMMdd to Date

I have a query that was working fine before a server migration and now is not working. I'm trying to convert all dates to a specific month and year, but I keep getting this error:
Conversion failed when converting date and/or time from character string.
Looking into the data, there are no null values in InputDate, which is a date data type column. When I run the Concat() function everything is formatted as 'YYYYMMdd', yet both CAST and CONVERT fail with the same error.
Is there an issue with my query that I'm not seeing?
SELECT RandoSTUFF,
DATEADD(day,2,CAST(CONCAT('2023','02',FORMAT(InputDate,'dd')) AS date)) AS MovedDate
FROM a_table_
I expect the issue is you have date values near the end of their months, and you're trying to compose the equivalent values for February, which is shorter.
So if you have an InputDate value of, say, 2022-12-31 and run the code in the question, it will extract the 31 and concat it with the other values, and you'll end up trying to do this:
CAST('20230231' as Date)
Of course, there is no such date.
As it is, it's not clear whether you want such an input to map to February 28 or March 3. To fix this, you'll need to rethink the problem so you only try to map to valid dates, and ensure the final result is more clearly defined. This is one of the many reasons it's almost always better to use Date/time functions instead of composing dates from strings.

Converting an unknown six digit date format, possibly some variant of Julian

I recently got access to a legacy database where all dates are stored in an unfamiliar format I'm unable to translate, my initial research makes me think this is a Julian date type, but it seems to be a bit off?
Thankfully there's one date column that has a normal counterpart to it, but there are a lot of other dates where only the six digit code exists.
Any ideas what these dates are, or more importantly, how to convert between these two formats?
EX:
LEGACY/NORMAL
152409/2018-04-13
152413/2018-04-17
152427/2018-05-01
It's an ancient MS-SQL database tied to an even more ancient COBOL program if that's relevant information.
It could be the number of Days since 1600-12-31
i.e. 1-Jan-1601 = 1 etc.
Would like to see dates from a different year to confirm
Cobol Date functions
As SaggingRuffus pointed out. Many dialects of Cobol have functions that convert dates To/From Days since 31-Dec-1600
These functions include:
INTEGER-OF-DATE converts YYYYMMDD date to Days-since 31-12-1600
INTEGER-OF-DAY converts YYYYDDD date to Days-since 31-12-1600
DATE-TO-INTEGER converts Days since 31-12-1600 to YYYMMDD
DAY-OF-INTEGER converts Days since 31-12-1600 to YYYDDD
How I came to the Answer
I noticed that:
152413 - 152409 = 4 and 2018-04-17 is 4 days after 2018-04-13
152427 - 152413 = 14 and 2018-05-01 is 14 days after 2018-04-17
It was than a matter of doing the Date calculation which gives 31-dec-1600.
I also knew there where date formats where the date was stored as the number of days from 1600/1601. A date in a different year would confirm the format
Adding to Bruce Martin's answer:
Even ancient SQL Server support DATEADD/DATEDIFF, you just have to modify the start date to 1900 instead of 1600 using the constant 109208 (the number of dates inbetween).
dateadd(day, (legacydatecol- 109208), 0) as legacy2date
datediff(day, '19000101', datecol ) + 109208 as date2legacy

2005 SQL Server Management Studio

Can someone interpret this query. I am aware that alias, conversion, and linked databases are involved, but not familiar placement of numbers "4,2".
set birthday = convert(datetime, left(a.dob,2)+ '/'+
right(left(a.dob,4),2)+'/'+
right(a.dob,2)+left(right(a.dob,4),2))
from
[plkfsql2k5\prod2k5].st_data.dbo.st_patient a
This left(a.dob,2)+ '/'+right(left(a.dob,4),2)+'/'+right(a.dob,2)+left(right(a.dob,4),2) nightmare of a substring concatenation is taking a date, probably stored as text (ugh) and returning it in a format that can be converted to a date with the convert(datetime, <textdate) formula it's wrapped in.
The text date appears to be in a format where the month is in the first 2 characters, the day is in the 3 and 4th characters and the year... well the years is stored instead of 1999 like 9919 because some psychopath designed this field...
So it takes this mmddyyYY format (that only a crazy person would use) and coverts it to mm/dd/YYyy and the n uses the convert(datetime, <text date>) function to make it into an actual date.
Note that if you are in a country that uses dd/mm/yyyy format, then my explaination may need to be tweaked as the incoming text value may be ddmmyyYY and converts it to dd/mm/YYyy. Still a crazy-banana's starting point though.

Unknown SQL coding issue in Oracle SQL Developer

I'm writing an SQL statment that is supposed to do a count based on a date range. But, for some reason no data is being returned. Before I try and filter the count with my date range, everything works fine. Here is that code.
SELECT
CR.GCR_RFP_ID
,S.RFP_RECEIVED_DT
,CR.GCR_RECEIVED_DT
,CT.GCT_LOB_IND
FROM ADM.GROUP_CHANGE_TASK_FACT CT
JOIN ADM.B_GROUP_CHANGE_REQUEST_DIM CR
ON CR.GROUP_CHANGE_REQUEST_KEY = CT.GROUP_CHANGE_REQUEST_KEY
JOIN ADM.B_RFP_WC_COVERAGE_DIM S
ON S. RFP_ID = CR.GCR_RFP_ID
WHERE CT.GCT_LOB_IND = 'WC'
AND CR.GCR_CHANGE_TYPE_ID IN ('10','20','30','50','60','70','80','90','100','110',
'120','130','140', '150','160','170','180','190','200',
'210','220','230','240','260','270','280','300','310',
'320','330','340','350','360','370','371','372')
AND S.RFP_AUDIT_IND = 'N'
AND S.RFP_TYPE_IND = 'A'
The date field I'm using is called CR.GCR_RECIEVED_DT. This is a new field a in the db and all the records are 01-JAN-00. But I'm still doing the count just to make sure I can grab the data. Now, I added this line:
AND CR.GCR_RECEIVED_DT LIKE '01-JAN-00'
just as a random test thing. I know all the dates are the same. And it works fine, no issues. So I remove that line and replace it with this:
AND CR.GCR_RECEIVED_DT BETWEEN '31-DEC-99' AND '02-JAN-00'
I used this small range to keep it simple. But even though 01-JAN-00 deffinetly falls between those two dates, no data is returned. I have no idea why this is happening. I even tried this line to:
AND CR.GCR_RECEIVED_DT = '01-JAN-00'
and I still don't get data returned. It only seems to work with LIKE. I have checked and the field is a date type. Any help wold be much appreciated.
If your NLS_DATE_FORMAT is set to DD-MON-YY then the apparent discrepancy between the first two results can be explained.
When you use LIKE it implicitly converts the date value on the left-hand side to a string for the comparison, using the default format model, and then compares that to the fixed string; and '01-JAN-00' is like '01-JAN-00'. You're effectively doing:
AND TO_CHAR(CR.GCR_RECEIVED_DT, 'DD-MON-YY') LIKE '01-JAN-00'
Using LIKE to compare dates doesn't really make any sense though. When you use BETWEEN, though, the left-hand side is being left as a date, so you're effectively doing:
AND CR.GCR_RECEIVED_DT BETWEEN TO_DATE('31-DEC-99', 'DD-MON-YY')
AND TO_DATE('02-JAN-00', 'DD-MON-YY')
... and TO_DATE('31-DEC-99', 'DD-MON-YY') is December 31st 2099, not 1999. BETWEEN only works when the first value is lower than the second (from the docs, 'If expr3 < expr2, then the interval is empty'). So you're looking for values bwteen 2099 and 2000, and that will always be empty. If your date model was DD-MON-RR, from the NLS parameter or explicitly via TO_DATE, then it would be looking for values between 1999 and 2000, and would find your records.
Your third result is a little more speculative but suggests that the values in your GCR_RECEIVED_DT field have a time component, or are not in the century you think. This is similar to the LIKE version, except this time the fixed string is being converted to a date, rather than the date being converted to a string; effectively:
AND CR.GCR_RECEIVED_DT = TO_DATE('01-JAN-00', 'DD-MON-YY')
If they were at midnight on 2000-01-01 this would work. Because it doesn't that suggests they are either some time after midnight, or maybe more likely - since you're using a 'magic' date in your existing records - they are another date entirely, quite possibly 1900-01-01.
Here are SQL Fiddles for just past midnight and 1900.
If the field will eventually have a time component for new records you might want to structure the condition like this, and use date literals to be a bit clearer (IMO):
AND CR.GCR_RECEIVED_DT >= DATE '2000-01-01'
AND CR.GCR_RECEIVED_DT < DATE '2000-01-02'
That will find any records at any time on 2000-01-01, and can use an index on that column if one is available. BETWEEN is inclusive, so using BETWEEN DATE '2000-01-01' AND '2000-01-02' would include any records that are exactly at midnight on the later date, which you probably don't want.
Whatever you end up doing, avoid relying on implicit conversions using NLS_DATE_FORMAT as one day it might not be set to what you expect, causing potentially data-corrupting or hard to find bugs; and specify the full four-digit year in the model if you can to avoid ambiguity.
try something like this:
WHERE TRUNC(CR.GCR_RECEIVED_DT) = TO_DATE('01-JAN-00','DD-Mon-YY')
TRUNC without parameter removes hours, minutes and seconds from a DATE.

How to use between clause for getting data between two dates?

I have date field in the database in the format 2012-03-17 19:50:08.023.
I want to create a select query which gives me the data collected in the March month.
But I am not able to achieve this.
I am trying following query.
select * from OrderHeader where
Convert(varchar,UploadDt,103) between '01/03/2013' and '31/03/2013'
and DistUserUniqueID like '6361%'
This query gives me data for all the dates.
select * from OrderHeader where
UploadDt between '01/03/2013' and '31/03/2013' and DistUserUniqueID like '6361%'
This query gives me the error as Msg 242, Level 16, State 3, Line 1
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Please help me resolve this.
Thanks in advance
The first query returns all dates because you are converting your column to a string. Not sure why you are doing this. So when you say BETWEEN '01/anything' AND '31/anything', when you consider it is now just a string, that is going to match all "dates" in the column, regardless of month and year, since your WHERE clause will cover every single day possible (well, with the exception of the 31st of months other than March, and the first day in January and February - so not all the data but a very large percentage). '15/11/2026', for example, is BETWEEN '01\03\2013' AND '31/03/2013'.
Think about that for a second. You have datetime data in your database, and you want to convert it to a string before you query it. Would you also convert salary to a string before comparing it? If so, the person making $70,000 will look like they are making more than the person making $690,000, since character-based sorting starts at the first character and doesn't consider length.
The second query fails because you are using a regional, ambiguous format for your dates. You may like dd/mm/yyyy but clearly your server is based on US English formatting where mm/dd/yyyy is expected.
The solution is to use a proper, unambiguous format, such as YYYYMMDD.
BETWEEN '20130301' AND '20130313'
However you shouldn't use BETWEEN - since this is a DATETIME column you should be using:
WHERE UploadDt >= '20130301'
AND UploadDt < '20130401'
(Otherwise you will miss any data from 2013-03-31 00:00:00.001 through 2013-03-31 23:59:59.997.)
If you really like BETWEEN then on 2008+ (you didn't tell us your version) you can use:
WHERE CONVERT(DATE, UploadDt) BETWEEN '20130301' AND '20130331'
More date-related tips here:
Dating Responsibly
Finally, when converting to VARCHAR (or any variable-length data types), always specify a length.
Rewrite the query as
select * from OrderHeader where
UploadDt between '01/03/2013' and '01/04/2013'
and DistUserUniqueID like '6361%'
or
select * from OrderHeader where
UploadDt between Convert(datetime,'01/03/2013', 103) and Convert(datetime,'01/04/2013',103)
and DistUserUniqueID like '6361%'