How to convert text to date entered as a date in sql? - sql

Data type is TEXT and entered as '20/11/2017' and when using MAX or MIN it ignores the month. I am trying to convert it into a date format for month to be considered as well.
CAST AND CONVERT do not seem to work as the following error returns
Msg 241, Level 16, State 1, Line 13
Conversion failed when converting date and/or time from character string.
Code:
SELECT
user_id,
record_id
--CAST(onSale AS date) AS onSale
--CONVERT(DATE, onSale) AS onSale,
--CONVERT(DATE, OffSale) AS OffSale
FROM (SELECT user_id,
record_id,
(SELECT MAX(value) AS Expr1
FROM UPLOADS.LINES AS SUH WITH (NoLock, ReadUncommitted)
WHERE (field_id = 4782) AND (record_id = UR.record_id)) AS onSale,
(SELECT MAX(value) AS Expr1
FROM UPLOADS.LINES AS SUH WITH (NoLock, ReadUncommitted)
WHERE (field_id = 4783) AND (record_id = UR.record_id)) AS OffSale
FROM UPLOADS.RECORDS AS UR WITH (NoLock, ReadUncommitted)
WHERE (module_id = 18)) AS DATA;
The end result would essentially be the MAX or MIN date with all three components being date,month and year. So if the user has entered two dates being 17/05/2018 and 17/04/2018 then the first should be shown if MAX is used.

You can use a format code when using CONVERT, and you can even use TRY_CONVERT to prevent errors from invalid dates. I also improved your code to make it simpler and more efficient.
SELECT [user_id],
record_id,
MAX(CASE WHEN SUH.field_id = 4782 THEN TRY_CONVERT( DATE, SUH.value, 103) END) AS onSale,
MAX(CASE WHEN SUH.field_id = 4783 THEN TRY_CONVERT( DATE, SUH.value, 103) END) AS OffSale
FROM UPLOADS.RECORDS AS UR
JOIN UPLOADS.LINES AS SUH ON SUH.record_id = UR.record_id
WHERE module_id = 18
GROUP BY [user_id],
record_id;

This is a slight improvement on Luis's answer in terms of the SQL:
SELECT ur.[user_id], ur.record_id,
MAX(CASE WHEN SUH.field_id = 4782 THEN TRY_CONVERT( DATE, SUH.value, 103) END) AS onSale,
MAX(CASE WHEN SUH.field_id = 4783 THEN TRY_CONVERT( DATE, SUH.value, 103) END) AS OffSale
FROM UPLOADS.RECORDS UR LEFT JOIN
UPLOADS.LINES AS SUH
ON SUH.record_id = UR.record_id AND
SUH.field_id IN (4782, 4783)
WHERE ur.module_id = 18
GROUP BY ur.[user_id], ur.record_id;
That said, your problem is that your data is not in the format you think it is. Hence, the problem with type conversions. As #marc_s says in a comment, you should be using SQL native and appropriate types which in this case is DATE. And you certainly should not be using deprecated types, such as TEXT (unless you really just mean VARCHAR() and don't realize that there is a deprecated TEXT type). If you are storing values in strings (because there are different types), you should use the standard format, either YYYYMMDD or YYYY-MM-DD.
You can find these values by running:
select suh.value
from uploads.lines suh
where suh.field_id in (4782, 4783) and
try_convert(date, suh.value, 103) is null and
suh.value is not null;
This can help you fix your data.
After you have fixed your data, you can also fix the type:
update uploads.lines
set suh.value = convert(varchar(255), convert(date, suh.value, 103), 112); -- this will convert the value to the default date format

Related

How to partially Match cell against another partial cell

I have a problem with two tables which I need to compare dates for the same reference. The problem is that
the dates are different formats and
superfluous data is also contained within both date cells.
Global
No. Date
1 1992-08-25 00:00:00.000
2 2015-05-19 00:00:00.000
3 2000-01-12 00:00:00.000
Local
No. Date
1 25.08.1992 00:00:00.000000000 GMT
1 28.08.1992 00:00:00.000000000 GMT
2 19.05.2015 00:00:00.000000000 GMT
3 12.01.2000 00:00:00.000000000 GMT
3 17.01.2000 00:00:00.000000000 GMT
Note that the date formats between the two tables differ and contain lots of time and zero data that is not needed. So ideally I would like to see the format as DD-MM-YYYY.
I would like to return only the Global and Local entries where the Local date differs from Global date. So from the data above, I would want to see:
No. Date No. Date
1 25-08-1992 1 28-08-1992
3 12-01-2000 3 17-01-2000
I would put my attempts so far, but to be honest I have no idea on how to tackle the partial cell matching and re-formatting.
Any ideas?
Update:
I tried a solution from #Sarslan and substituted my table and field names which resulted in this:
WITH G AS
(
SELECT [UPC], CONVERT(DATE,LEFT([GLOBAL RELEASE DATE], CHARINDEX(' ',
[GLOBAL RELEASE DATE])),120) [Date] FROM [dsched_migration].[emi].
[EMI_Global]
)
,L AS
(
SELECT [UPC], CONVERT(DATE,LEFT([TERR_REL_DATE], CHARINDEX(' ',
[TERR_REL_DATE])),104) [Date] FROM [dsched_migration].[emi].
[terr_release_dates]
)
SELECT
G.UPC, CONVERT(VARCHAR,G.Date,105) [GLOBAL RELEASE DATE],
L.UPC, CONVERT(VARCHAR,L.Date,105) [TERR_REL_DATE]
FROM
G INNER JOIN L ON L.UPC = G.UPC
WHERE L.Date <> G.Date
I keep getting this error:
Msg 241, Level 16, State 1, Line 7
Conversion failed when converting date and/or time from character string.
select * from
(
select a.no, to_char(a.date,'DD-mm-YYY') Date1 , b.no, to_char(b.date,'DD-mm-YYY') Date2
from Global a inner join Local b on (a.no=b.no)
)
where Date1<>Date2;
Could you try this?
;WITH G AS
(
SELECT [No], CONVERT(DATE,LEFT([Date], CHARINDEX(' ', [Date])),120) [Date] FROM [GLobal]
)
,L AS
(
SELECT [No], CONVERT(DATE,LEFT([Date], CHARINDEX(' ', [Date])),104) [Date] FROM [Local]
)
SELECT
G.No, CONVERT(VARCHAR,G.Date,105) [Date],
L.No, CONVERT(VARCHAR,L.Date,105) [Date]
FROM
G INNER JOIN L ON L.No = G.No
WHERE L.Date <> G.Date
Result
No Date No Date
----------- ------------------------------ ----------- ------------------------------
1 25-08-1992 1 28-08-1992
3 12-01-2000 3 17-01-2000
When you have some formatted string that format will never change you can simplify it like this - this will also give you more flexibility -:
;with tg as (
select [No],
-- Format is : yyyy-mm-dd
left([Date], 4) yyyy, substring([Date], 6, 2) mm, substring([Date], 9, 2) dd
from g
), tl as (
select [No],
-- Format is: dd-mm-yyyy
substring([Date], 7, 4) yyyy, substring([Date], 4, 2) mm, left([Date], 2) dd
from l
)
select *
from tg
inner join tl
on tg.[No] = tl.[No]
and not (tg.yyyy = tl.yyyy and tg.mm = tl.mm and tg.dd = tl.dd);
Thanks for all replies but found a solution:
Created a new column then ran this query to confirm the conversion:
SELECT '19.10.2009 00:00:00.000000000 GMT',
CONVERT(datetime, LEFT('19.10.2009 00:00:00.000000000 GMT',10), 104)
This gave me the right format then I ran the following query to update the new column with the formatted date:
update LocalDate
set REL_DATE = CONVERT(datetime, LEFT(TERR_REL_DATE,10), 104)
Luckily my Global date was already in datetime so I then simply joined the two tables and ran my comparison against the new updated time

Using an Aggregate function with a sub query

We get a new batch of widgets each month. We know the product codes of these widgets which will be is stock, waiting to be used. Each also has an availability date, after which it can be used.
Table WidgetStock
Columns: WidgetID, AvailabilityDate,
Another table has the uses of the widget, ie when it was first used.
Table WidgetsUsed
Columns: datetime, Operator
I'd like to see by day and hour the amount of fresh widgets that I have used for the first time, since the start of the month. The widgets will be used multiple times, so a simple distinct count by hour is not really enough, as widgets would be double counted.
In my mind this would require looking at a list of available numbers, which is updated for each line of a group by query.
The below query will not work, but hopefully it shows what I am trying to achieve:
declare #StartofMonth datetime
set #StartofMonth = '20160901'
select CONVERT(varchar, wu.datetime, 103)'Date'
, convert(char(2), wu.datetime, 108)'Hour'
--Problem Line below
, SUM(case when wu.StockNo in (select ba.NUMBER
from widgetStock ba
where availability_date between CONVERT(varchar, wu.datetime, 103) and #StartofMonth) then 1 else 0 end) 'Number Used'
from widgetsUsed wu
left join widgetStock ws on wu.StockNo = ws.NUMBER
where wu.OPERATOR = 'WidgetWorld'
and DATETIME between '20160914' and '20160916'
group by CONVERT(varchar,wu.datetime,103), convert(char(2), wu.datetime, 108)
Any help with this is appreciated. Thanks in advance.
If understood your requirement then below script may solve your problem
declare #StartofMonth datetime
set #StartofMonth = '20160901'
select CONVERT(varchar, wu.datetime, 103)'Date'
, convert(char(2), wu.datetime, 108)'Hour'
, SUM(ISNULL(ba.NUMBER,0)) 'Number Used'
from widgetsUsed wu
left join widgetStock ws on wu.StockNo = ws.NUMBER
LEFT JOIN widgetStock ba ON wu.StockNo = ba.NUMBER AND availability_date between CONVERT(varchar, wu.datetime, 103) and #StartofMonth
where wu.OPERATOR = 'WidgetWorld'
and DATETIME between '20160914' and '20160916'
group by CONVERT(varchar,wu.datetime,103), convert(char(2), wu.datetime, 108)

SQL Server DATE conversion error

Here is my query:
SELECT
*
FROM
(SELECT
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE
APV.DateValue < GETDATE()
It results in the following error:
Conversion failed when converting date and/or time from character string.
If you comment out the WHERE APV.DateValue < GETDATE() clause then there is no error and I get the 300+ rows. When I enable the WHERE clause I get the error.
So you are going to tell me my data is jacked up right? Well that's what I thought, so I tried to figure out where the problem in the data was, so I started using TOP() to isolate the location. Problem was once I use the TOP() function the error went away, I only have 2000 rows of data to begin with. So I put a ridiculous TOP(99999999) on the inner SELECT and now the entire query works.
The inner SELECT returns the same number of rows with or without the TOP().
WHY???
FYI, this is SQL that works:
SELECT
*
FROM
(SELECT TOP(99999999)
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4
) AS APV
WHERE
APV.DateValue < GETDATE()
The problem that you are facing is that SQL Server can evaluate the expressions at any time during the query processing -- even before the WHERE clause gets evaluated. This can be a big benefit for performance. But, the consequence is that errors can be generated by rows not in the final result set. (This is true of divide-by-zero as well as conversion errors.)
Fortunately, SQL Server has a work-around for the conversion problem. Use try_convert():
TRY_CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
This returns NULL rather than an error if there is a problem.
The reason why some versions work and others don't is because of the order of execution. There really isn't a way to predict what does and does not work -- and it could change if the execution plan for the query changes for other reasons (such as table statistics). Hence, use try_convert().
My guess is that your date is such that APV.VALUE contains also data that cannot be converted into a date, and should be filtered out using the other criteria?
Since SQL Server can decide to limit the data first using the criteria you have given:
APV.DateValue < CONVERT( DATETIME, GETDATE(),101)
And if there is data that cannot be converted into the date, then you will get the error.
To make it more clear, this is what is being filtered:
CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
And if there is any data that cannot be converted into a date using 101 format, the filter using getdate() will fail, even if the row would not be included in the final result set for example because AP.PropertyName does not contain DATE.
Since you're using SQL Server 2012, using try_convert instead of convert should fix your problem
And why it works with top? In that case SQL Server cannot use the criteria from the outer query, because then the result might change, because it might affect the number of rows returned by top
Because number of records in the table < 999..99. And regarding the error it seems like SQL engine evaluates the WHERE clause after converting to date so you can try this:
SELECT *
FROM (
SELECT A.Name
, AP.PropertyName
, APV.Value AS [PropertyValue]
,
CASE
WHEN SDATE(APV.Value) = 1
THEN CONVERT( DATETIME, APV.VALUE, 101)
ELSE NULL
END AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP
ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV
ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND LEN( SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE APV.DateValue IS NOT NULL AND APV.DateValue < GETDATE()

SQL Issue querying database between two dates

I have the following records in the DB below is the created date for each record.
2013-11-09 12:55:43.000
2013-10-29 19:01:53.000
2013-10-29 04:59:42.000
My SQL query looks like this
Select d.Name as DealerName, Sum(c.CommissionAmount) as CommissionAmount
from Dealer d
Left join Commission c on c.Dealerid = d.DealerId
where c.CreatedDate between isnull(#FromDate, c.CreatedDate) and isnull(#ToDate, c.CreatedDate)
Group by d.Name
Order by CommissionAmount desc
When I enter the following dates in to my search functionality
From date = 29/10/2013
To date = 09/11/2013
It only returns one record, when it should return three, yet if I leave From date as it is and pass in null for To date I get two records back
Can someone tell me what I'm doing wrong here?
Thanks
Try this:
When You are using Dates in where clause Always use Same casting on both sides
Select d.Name as DealerName, Sum(c.CommissionAmount) as CommissionAmount
from Dealer d
Left join Commission c on c.Dealerid = d.DealerId
where CAST(c.CreatedDate as DATE) between
CAST(isnull(#FromDate, c.CreatedDate) as DATE) and
CAST(isnull(#ToDate, c.CreatedDate) as DATE)
Group by d.Name
Order by CommissionAmount desc
You can do this by using tow ways one is
1. CAST
CAST(c.CreatedDate as DATE)
2. CONVERT
CONVERT(varchar(10), c.CreatedDate)
Here is the both the ways that you can achieve.
1. where
CONVERT(varchar(10), c.CreatedDate)
between
isnull(#FromDate, c.CreatedDate)
and
isnull(#ToDate, c.CreatedDate)
2. where
CAST(c.CreatedDate as DATE)
between
isnull(#FromDate, c.CreatedDate)
and
isnull(#ToDate, c.CreatedDate)
Difference between cast & convert is You can Apply any style format you need in the CONVERT function .There are many date time format availabe for CONVErT function Refer this link You will get all the styple format in the SQL.
Syntax for the COnvert is
CONVERT ( data_type [ ( length ) ] , expression [ , style ] )
where expression [ , style ] is optional field.
CAST :
Cast is available after the version of SQL 2005. cast also Converts an expression of one data type to another in SQL Server.
Syntax
CAST ( expression AS data_type [ ( length ) ] )
[ ( length ) ] is optional field in Cast
Try This
SELECT d.Name as DealerName, Sum(c.CommissionAmount) as CommissionAmount
FROM Dealer d
LEFT JOIN Commission c on c.Dealerid = d.DealerId
WHERE CONVERT(VARCHAR(10),CAST(c.CreatedDate AS DATE),103)
BETWEEN isnull(#FromDate, c.CreatedDate) and isnull(#ToDate, c.CreatedDate)
Group by d.Name
Order by CommissionAmount desc
The problem is u have defined the variables without time So the #todate will be like '2013-11-09 00:00:00.000'.
But in the table date has time. Between operator will not consider this date '2013-11-09 12:55:43.000' since it is higher than the todate u have mentioned thats y you are getting two rows.
so try this.
CREATE TABLE #temp
(dates DATETIME)
INSERT INTO #temp
VALUES ('2013-11-09 12:55:43.000'),
('2013-10-29 19:01:53.000'),
('2013-10-29 04:59:42.000')
DECLARE #from VARCHAR(50)='29/10/2013',
#to VARCHAR(50) ='09/11/2013'
SELECT *
FROM #temp
WHERE (#from is not null and #to is not null and Cast(dates AS DATE) BETWEEN CONVERT(DATE, #from, 103) AND CONVERT(DATE, #to, 103) ) or 1=1
SQL FIDDLE DEMO

i need to use the sum of the value in 1 column as part of a ref in another column in a view

i have a view as below.
SELECT TOP (100) PERCENT 'SA' AS Doc_Type1, 'A' + SUBSTRING('000000', 1, 6 - LEN(CAST(dbo.companies.companyId AS varchar(10))))
+ CAST(dbo.companies.companyId AS varchar(10)) AS Client_ID, 1200 AS Bank_Nom, 0 AS Department, CONVERT(nvarchar(20),
dbo.invoices.invoiceDatePaid, 103) AS Cleared_Date, 'Bacs' AS Payment_type, dbo.invoices.invoiceId, dbo.invoices.invoiceTotal AS Value, '9' AS vat,
' ' AS bllank, 1 AS Ex_rate
FROM dbo.invoices INNER JOIN
dbo.companies ON dbo.invoices.invoiceCompanyId = dbo.companies.companyId
WHERE (dbo.invoices.invoiceDatePaid >= DATEDIFF(DAY, 1, CURRENT_TIMESTAMP)) AND (dbo.invoices.invoiceDatePaid < DATEDIFF(DAY, 0,
CURRENT_TIMESTAMP)) AND (dbo.companies.companyPaymentType = 3)
ORDER BY dbo.invoices.invoiceId DESC
In the Payment_Type column i want to add the SUM of the Value column to the word 'Bacs' so it reads 'Bacs £sum' to 2 decimal places. Could you help please, regards and thanks for all the help and suggestions already provided
I'm not very much clear to what exactly you need. You need complete sum of entire column to be displayed or in a group manner, but here is what you can try..Add the sum(Value) after converting it to varchar,which is necessary as two data types has to be varchar to concenate and group by all the remaining columns..something like this
....
,'Bacs'+cast(sum(dbo.invoices.invoiceTotal)
as varchar) AS Payment_type
...
group by all remaining columns
...
order by clause
I don't know whether it even close to what you need but it's just a try to help :-)