SQLite compare dates - sql

I have this SQL-Statement:
SELECT Geburtsdatum FROM Kunde
WHERE Geburtsdatum BETWEEN '1993-01-01' AND '2000-01-01'
but I get some weird results, like: 2.02.1990
'Geburtsdatum' is a DATE
Any suggestions or solutions?
my table-structure:
CREATE TABLE Kunde (
Kunde_ID INTEGER NOT NULL ,
Card INTEGER ,
Vorname VARCHAR(255) NOT NULL ,
Nachname VARCHAR(255) NOT NULL ,
Ort VARCHAR(255) NOT NULL ,
Strasse VARCHAR(255) NOT NULL ,
Postleitzahl VARCHAR(10) NOT NULL ,
Mail VARCHAR(255) ,
Telefonnummer VARCHAR(255) ,
Geburtsdatum DATE NOT NULL ,
Beitrittsdatum DATE NOT NULL ,
Geschlecht INTEGER NOT NULL ,
Land VARCHAR(255) NOT NULL DEFAULT 'Österreich' ,
Bankname VARCHAR(255) ,
Bankleitzahl VARCHAR(255) ,
Kontonummer VARCHAR(255) ,
GroupID INTEGER NOT NULL ,
Besucher INTEGER ,
Access BOOLEAN ,
image BLOB NULL ,
writeDate DATE ,
drinkAbo BOOLEAN ,
PRIMARY KEY (Kunde_ID) )

From the documentation:
SQLite does not have a storage class set aside for storing dates and/or times.
So your column isn't exactly stored as a date. Reading further, we learn that columns specifed as DATE are actually stored as NUMERIC using affinity rule 5.
Going back up to section 1.2:
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
Good. So let's try:
SELECT Geburtsdatum FROM Kunde
WHERE Geburtsdatum
BETWEEN julianday('1993-01-01') AND julianday('2000-01-01');
Oddly enough, SQL Fiddle seems to store DATEs as strings and the above doesn't work. In this case, the following should:
SELECT Geburtsdatum FROM Kunde
WHERE date(Geburtsdatum)
BETWEEN date('1993-01-01') AND date('2000-01-01');
Additionally, in your case you seem to be getting some strange (read: localized) format returned. I wonder if it really is a string in your case too, just with a different format. You could try:
SELECT Geburtsdatum FROM Kunde
WHERE strftime('%d.%m.%Y', Geburtsdatum)
BETWEEN date('1993-01-01') AND date('2000-01-01');

Someone had the same problem and got it resolved. (use datetime function before comparison)
See SQLite DateTime comparison
Excerpt:
Following the datetime function and having a string format as YYYY-MM-DD HH:mm:ss i achieved good results as follows
select *
from table_1
where mydate >= Datetime('2009-11-13 00:00:00')
and mydate <= Datetime('2009-11-15 00:00:00')
--EDIT--
You are basically comparing strings. Which is why the unexpected behavior. Convert to datetime using the function right before comparison and it should work.

To be able to compare dates, you must store them in one of SQLite's supported date formats, such as a JJJJ-MM-TT string. Your dates are stored as strings in a localized date format which is not recognized by SQLite.
If the most significant field is not at the start of the string, string comparisons will not work for dates.
With the values currently in your table, you will not be able to do any comparisons.

Related

Error message when inserting date into table

when I try to insert my date values in all my other tables it works fine, except of one. Whatever format I try I always get the error, that the inserted value couldn't be converted from an input char to the expected date format.
That's how I insert my values
-- ServiceTicket
INSERT INTO ServiceTicket
VALUES ('90000', '01-5-2019', '50000', '10000', '70000', 200.00, 100.00, 5.00, 350.00) --Error converting into DATE type
And this is the table structure:
CREATE TABLE dbo.ServiceTicket (
ticketIssueNo INT NOT NULL IDENTITY(1,1) PRIMARY KEY, --Identity autoincrements
serviceDate DATE NOT NULL,
vehicleId CHAR(8) NOT NULL,
customerId CHAR(8) NOT NULL,
inspectionId CHAR(8) NOT NULL,
serviceCost DECIMAL(10,4) NOT NULL CHECK(serviceCost BETWEEN 0.0 AND 99999.0) DEFAULT 0.0,
inspectionCost DECIMAL(10,4) NOT NULL CHECK(inspectionCost BETWEEN 0.0 AND 99999.0) DEFAULT 0.0,
repairCost DECIMAL(2,2) NOT NULL CHECK(repairCost BETWEEN 0.0 AND 99999.0) DEFAULT 0.0,
GST DECIMAL(10,4) NOT NULL DEFAULT 0.0,
amountDue DECIMAL(10,4) NOT NULL CHECK(amountDue BETWEEN 0.0 AND 99999.0) DEFAULT 0.0,
FOREIGN KEY(vehicleId) REFERENCES Vehicle(vehicleId)
ON UPDATE NO ACTION,
FOREIGN KEY(inspectionId) REFERENCES VehicleInspection(inspectionId)
ON UPDATE NO ACTION,
FOREIGN KEY(customerId) REFERENCES Customer(customerId)
ON UPDATE NO ACTION
)
GO
I might overlook something.
Always list the columns when writing an insert statement.
Here's an exact equivalnet of your insert statement, written properly, based on the DDL you've published:
INSERT INTO ServiceTicket
(serviceDate, vehicleId , customerId, inspectionId , serviceCost , inspectionCost, repairCost, GST , amountDue) VALUES
('90000' , '01-5-2019' , '50000' , '10000' , '70000' , 200.00 , 100.00 , 5.00 , 350.00)
I've used tabs so that each value would be perfectly aligned with the column it goes into, that helps a lot when you have a long list of columns.
As you can clearly see, the serviceDate gets the value '90000' - while it shoud clearly be '01-5-2019'
Always use ISO8601 format for string representation of date / datetime values.
Any other format is culture dependent, and the worst thing about it is that it depends on the default language of the login - so different logins might have different results if you use a culture-dependent format. The ISO8601 standard provides two alternatives for datetime formats: yyyy-mm-ddThh:mm:ss or yyyymmddThhmmss. If you are inserting only a date only string value into a DateTime data type column / variable, be sure to use only the second (yyyymmdd) format - because yyyy-mm-dd is still culture dependent with DateTime (but not with Date or with DateTime2 - that's one more reason why you should never use DateTime again.
So the proper way of writing the insert statement would be this:
INSERT INTO ServiceTicket
(serviceDate, vehicleId , customerId, inspectionId , serviceCost , inspectionCost, repairCost, GST , amountDue) VALUES
('2019-05-01', '90000' , '50000' , '10000' , '70000' , 200.00 , 100.00 , 5.00 , 350.00)
(That is, assuming 01-5-2019 stands for May 1st. If it stands for January 5th, it should be 2019-01-05).
The date format '01-5-2019' which you are using does not appear to be a default accepted date literal by SQL Server. Try using '20190501':
INSERT INTO ServiceTicket (serviceDate, ... <other columns>)
VALUES
('20190501', ...);
Note that YYYYMMDD is an unambiguous unseparated ISO format, as the documentation discusses.
The format for inserting date type in SQL is YYYY-dd-MM, You need to change it to '2019-05-01'
Change your date format from '01-5-2019' to '2019-05-01'.
Instead passing date as '01-5-2019' pass CAST('01-5-2019' AS DATE).
The default format for the year data type in SQL is YYYY-MM-DD(If you've not changed it before) Info. So as described here, you should convert the input string into a valid date type.

Datetime column cannot be pesisted

I have this SQL statement to create a table that stores the JSON string data and the event time found in that JSON string.
CREATE TABLE [dbo].[EventLog]
(
[EventID] INT NOT NULL IDENTITY(1,1),
[EventTime] AS CAST(JSON_VALUE(RawEvent, '$.EventTime') AS DATETIME ) PERSISTED,
[RawEvent] NVARCHAR(MAX) NOT NULL
)
However I get the following error below when I run this, I assume SQL Server does not know if the value fits DATETIME? is there a way to get this column defined?
Msg 4936, Level 16, State 1, Line 26
Computed column 'EventTime' in table 'Event' cannot be persisted because the column is non-deterministic.
You can use CONVERT with dates and have deterministic behavior as long as you specify certain date styles. As per the docs here, with the most common JavaScript date formats (since you are converting from JSON), you can use style 126 or 127, which are ISO8601 and ISO8601 with time zone. Your table, then, could be specified like this:
CREATE TABLE [dbo].[EventLog]
(
[EventID] INT NOT NULL IDENTITY(1,1),
[EventTime] AS CONVERT(DATETIME, JSON_VALUE(RawEvent, '$.EventTime'), 126) PERSISTED,
[RawEvent] NVARCHAR(MAX) NOT NULL
)
Alas, this is explained in the documentation:
CAST Deterministic unless used with datetime, smalldatetime, or sql_variant.
You may be able to parse the date and reconstruct the value using datefromparts() or datetimefromparts().

nvarchar or varchar or date in joins of SQL Server

I have a management project developed in Web using SQL Server 2008 R2 and Windows Application using SQL Server CE 4.0.
Both uses almost same database structure. I have a fees table as :
TABLE [fees]
(
[feeid] bigint NOT NULL IDENTITY(1,1),
[acno] int NULL DEFAULT 0,
[billingmonth] nvarchar(10) NULL,
[oldbal] numeric(18,2) NULL DEFAULT 0,
[duedtamt] numeric(18,2) NULL DEFAULT 0,
[afterdtamt] numeric(18,2) NULL DEFAULT 0,
[bal] numeric(18,2) NULL DEFAULT 0,
[depamt] numeric(18,2) NULL DEFAULT 0,
[totdpo] numeric(18,2) NULL DEFAULT 0,
[depdt] datetime NULL
)
billingmonth will always use format MMM-yyyy eg. Jan-2018
BillingMonth uses various joins (inner and left outer join) in other tables.
How to increase performance of joins with BillingMonth ? , should i :
Convert nvarchar to varchar ( as it will always store Month in SQL2008R2 )
Convert nvarchar to datetime ( as first day of month 01-MMM-yyyy in SQL Server CE and SQL Server 2008 R2)
Storing date values as nvarchar is not recommended at all
There are many suggestions to increase the join performance:
Use Date datatype
Use two numeric field month and year instead of one varchar field (tinyint for month, smallint for year, they can be used only for joining purpose)
Note that: AS #Pரதீப் mentioned, When you store month and year separately, you need to do some integer manipulations when searching for date ranges

Inserting date in sql server

When I try to execute this query
INSERT INTO StateRegion
( FullName ,
Abbreviation ,
RegionType ,
Admitted ,
Capital
)
VALUES ( 'Alabama' ,
'AL' ,
1 ,
'1819-Dec-14' ,
'Montgomery'
);
it gives me error sql date conversion error :
Conversion failed when converting date and/or time from character
string
Admitted is a Date type.
The issue is I can not change this format : 1819-Dec-14, is it possible to add convert method to the query above ?
Table definition :
CREATE TABLE StateRegion
(
ID bigint PRIMARY KEY IDENTITY(1,1),
FullName varchar(50) NOT NULL,
Abbreviation varchar(2) NOT NULL,
RegionType smallint NOT NULL,
Admitted date NULL,
Capital varchar(50) NULL
);
The month name part of that date format is interpreted according to the language of the login.
You can change the default language of the login to US English or British English if you must work with that format or issue a
Set language english
To set the format at run time before the problematic query then optionally switch it back afterwards.
If you have the choice using yyyy-mm-dd or yyyymmdd would be preferable formats for date literals though that both avoid this issue when casting to date.
Use a parameterized query. Parameterization will send the date to the server in binary, avoiding any string conversions which depend upon the client locale.
Example in C#:
SqlCommand sqc = new SqlCommand("INSERT INTO MyTable (DateColumn) VALUES (#date)", con);
sqc.Parameters.AddWithValue("#date", new DateTime(1819, 12, 14));
If you are running this from an interactive batch (SQL Server Management Studio, or similar), use SET LANGUAGE to ensure the dates are parsed correctly:
SET LANGUAGE ENGLISH;
INSERT INTO StateRegion (FullName, Abbreviation, RegionType, Admitted, Capital)
VALUES ('Alabama', 'AL', 1, '1819-Dec-14', 'Montgomery');
SqlFiddle example showing correct parsing
Do not confuse storage format and display format. Just because the server store the date in the database as '1819-12-14' you can use a custom formatting output for the display.
Then correct for the display issue with a function such as:
CREATE FUNCTION usp_FormatedDateString (#Date Date)
RETURNS VARCHAR(50)
AS
BEGIN
DECLARE #RETURN AS VARCHAR(50)
DECLARE #I INT = 0
DECLARE #M AS VARCHAR(100) = 'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'
SET #RETURN = CAST(DATEPART(YEAR,#Date) AS VARCHAR(4))
SET #I = DATEPART(MONTH, #Date) - 1
SET #RETURN = #RETURN + '-' + SUBSTRING(#M,(#I*3)+1,3)+'-'+ CAST (DATEPART(DAY,#Date) AS VARCHAR(2))
RETURN #RETURN
END
GO
Then when you display the results:
SELECT FullName,Abbreviation,RegionType, dbo.usp_FormatedDateString (Admitted) as Admitted, Capital FROM StateRegion
It will display correct and store correctly.
You can try to use an explicit format for the conversion. You are not explaining why you can't change the format, but I imagine that you are reading the values somehow that are already stored as that. You can use CONVERT:
DECLARE #Admitted VARCHAR(11);
SET #Admitted = '1819-Dec-14'
SELECT CONVERT(DATETIME,RIGHT(#Admitted,2)+' '+
SUBSTRING(#Admitted,6,3)+' '+
LEFT(#Admitted,4),106);
Chang datatype of date to VARCHAR

Datetime search in sql

SQL FIDDLE
CREATE TABLE STUDY
(
[ID][INT],
STUDY_DATE VARCHAR(40),
START_TIME VARCHAR (40),
END_TIME VARCHAR (40)
)
INSERT INTO STUDY VALUES(1,'2013-12-23','11:30:00','11:31:00')
SELECT STUDY_DATE,START_TIME,END_TIME
FROM STUDY
WHERE (STUDY_DATE >='2013-12-22'
AND CAST(START_TIME AS DATETIME) >='19:12:01')
AND (STUDY_DATE <='2013-12-23'
AND CAST(END_TIME AS DATETIME) <='13:12:14')
i have to fetch records from table with above criteria..
however my STUDY_DATE criteria is fullfill but START_TIME criteria not.
thats the reason records not fetch from table..
What should i do.
In your example - '11:30:00' IS NOT more or equal '19:12:01' (when casted to datetime, but it doesnt matter).
Do what people suggest - store date as datetime, dont use varchars for it.
Upd:
Ok, if you cant change your table:
SELECT STUDY_DATE,START_TIME,END_TIME
FROM STUDY
WHERE CAST(STUDY_DATE + 'T' + START_TIME AS DATETIME) >='2013-12-22T19:12:01'
AND CAST(STUDY_DATE + 'T' + END_TIME AS DATETIME) <='2013-12-23T13:12:14'
I don't understand why you store your date fields as varchar...
When you cast START_TIME field as DATETIME its representation is YYYY-MM-DD HH:MM:SS.mmm
So you can't compare your casted field with 19:12:01 but you must take the time part (DATEPART function can help you) and then you'll compare with your constant (19:12:01).
I've seen your SqlFiddle. You can't cast as datetime the value 11:30:00.
Solution A: Change the field type (adviced)
Solution B: Compare as string your values, because is a well formed string (not adviced)
Although it's better use proper data types (datetime in this case) if you can't change data types for this fields you can add computed columns and even create indexes on them (for PERSISTED).
CREATE TABLE #STUDY
(
[ID][INT],
STUDY_DATE VARCHAR(40),
START_TIME VARCHAR (40),
END_TIME VARCHAR (40),
START_DATETIME AS CAST(REPLACE(STUDY_DATE,'-','')+' '+START_TIME as datetime),
END_DATETIME AS CAST(REPLACE(STUDY_DATE,'-','')+' '+END_TIME as datetime)
)
INSERT INTO #STUDY VALUES(1,'2013-12-23','11:30:00','11:31:00')
SELECT STUDY_DATE,START_TIME,END_TIME
FROM #STUDY
WHERE START_DATETIME >='20131222 19:12:01'
AND END_DATETIME <='20131223 13:12:14'
drop table #STUDY