How to skip values that have NULL values in a TSQL query? - sql

I have this rather complex query:
SELECT distinct
v.KodQ, v.DodPeriodika,
v.GodGP, v.Periodika as Period,
k.Oblast, k.KratokNazivSI,
k.NazivSI, k.Periodika,
v.rKod, r.Naziv,
v.rDatum,
v.IT, v.Primerok, v.BrojIE,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
FROM GP.dbo.MyTable1 AS v
INNER JOIN GP.dbo.MyTable2 as k
ON k.KodSI = v.KodQ AND k.DodObr = v.DodPeriodika
INNER JOIN GP.dbo.MyTable3 AS r
ON r.rKod = v.rKod
WHERE v.GodGP = GodGP and CHARINDEX('-', RefPeriodDo, 0) != 0
I need to convert v.RefPeriodOd and v.RefPeriodDo from this format '31-Dec-2017' to this format '31/12/2017'.
Yes I know saving DateTime as string(varchar) is bad idea, but the application is now in use so I cannot really do QA at the moment and refactor my table.
I am using this statement:
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
But the problem is, v.RefPeriodOd and v.RefPeriodDo can have a NULL values and also values in the format: '31/12/2017'
If I remove this condition:
CHARINDEX('-', RefPeriodDo, 0) != 0
I get this error:
The conversion of a nvarchar data type to a datetime data type
resulted in an out-of-range value.
How can I add some conditions in the query?
Does IF statement exists in TSQL?

Change
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd
for
CASE
WHEN CHARINDEX('-', RefPeriodDo, 0) != 0
THEN CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103)
END as RefPeriodOd
And remove the filter in the WHERE.
"IFs" are expressed with the CASE clause if inside SELECT statements, and the most common syntax is the following:
CASE
WHEN 1stCondition THEN 1stValue
WHEN 2ndCondition THEN 2ndValue
ELSE DefaultValue -- Else is optional
END
Conditions are evaluated in order, and if no ELSE is issued, then NULL is returned.

Try to add to the where the following:
WHERE (v.RefPeriodOd is not null and v.RefPeriodOd <> '')
AND (v.RefPeriodDo is not null and v.RefPeriodDo <> '')

Note:
You cannot put the condition in the WHERE clause. The filtering is not necessarily before the expressions in the SELECT.
You should always include a length for strings in SQL Server.
The right way to handle this is try_convert():
TRY_CONVERT(varchar(255), TRY_CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd,
TRY_CONVERT(varchar(255), TRY_CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
TRY_CONVERT() is available since SQL Server 2012. Before that, you needed to use a CASE to avoid conversion errors.
In my opinion, the filter condition should be:
RefPeriodDo LIKE '%-%'
I think this is easier to write and to read.

Try this:
SELECT distinct
v.KodQ, v.DodPeriodika,
v.GodGP, v.Periodika as Period,
k.Oblast, k.KratokNazivSI,
k.NazivSI, k.Periodika,
v.rKod, r.Naziv,
v.rDatum,
v.IT, v.Primerok, v.BrojIE,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
FROM GP.dbo.MyTable1 AS v
INNER JOIN GP.dbo.MyTable2 as k
ON k.KodSI = v.KodQ AND k.DodObr = v.DodPeriodika
INNER JOIN GP.dbo.MyTable3 AS r
ON r.rKod = v.rKod
WHERE v.GodGP = GodGP AND ISNULL(v.RefPeriodOd,'')<>'' AND ISNULL(v.RefPeriodDo,'')<>''
Filter the rows using WHERE:
WHERE v.GodGP = GodGP AND ISNULL(v.RefPeriodOd,'')<>'' AND ISNULL(v.RefPeriodDo,'')<>''

Give this as try
Note the double use of 103
declare #D table (id int identity primary key, dt varchar(20));
insert into #D (dt) values (null), ('messy'), ('31-Dec-2017'), ('31/12/2017'), ('1/12/2017');
select d.dt
, TRY_CONVERT(DATETIME, d.dt, 103) as dt103
, isnull(TRY_CONVERT(varchar(20), TRY_CONVERT(DATETIME, d.dt, 103), 103), d.dt) dt103var
from #D d;
dt dt103 dt103var
-------------------- ----------------------- --------------------
NULL NULL NULL
messy NULL messy
31-Dec-2017 2017-12-31 00:00:00.000 31/12/2017
31/12/2017 2017-12-31 00:00:00.000 31/12/2017
1/12/2017 2017-12-01 00:00:00.000 01/12/2017

Related

SQL Date as INT to Date for Query

I have a query built on the msdb..sysjobhistory table the MSDB database of my SQL Server. I want to be able to only give me back the stuff with the previous date. (in this example, 1/14/2015 would be yesterday) How do I go about this when the run_date information is in YYYYMMDD Integer format?
SELECT server
, jh.run_date
, jh.run_time
, j.name
, jh.run_duration
, jh.step_name
, run_status
, message
FROM msdb..sysjobhistory jh
INNER JOIN msdb..sysjobs j ON jh.job_id = j.job_id
WHERE jh.step_id = 0
Please advise.
-Nick
You could try converting that INT first to a VARCHAR and then using the 112 "Style" (noted on the MSDN page for Cast and Convert), convert that to a real DATETIME. For example:
SELECT CONVERT(DATETIME, CONVERT(VARCHAR(10), 20150115), 112)
Of course, doing that alone would invalidate an index on the [run_date] field, if there is one. If that is the case, then you can just do the DATEADD to substract a day and then convert back to VARCHAR and then to INT. For example:
SELECT CONVERT(INT,
CONVERT(VARCHAR(10),
DATEADD(DAY,
-1,
CONVERT(DATETIME, CONVERT(VARCHAR(10), 20150115), 112)
),
112
)
);
On my SQL Server 2012 instance there is no index on [run_date], but might be best to still not wrap a field around a function.
If just using a DATETIME value, such as provided by GETDATE(), it would look like:
WHERE jh.step_id = 0
AND jh.run_date = CONVERT(INT,
CONVERT(VARCHAR(10),
DATEADD(DAY, -1, GETDATE()),
112)
)

How to standardise a column of mixed date formats in T-SQL

Got a table in SQL Server which contains a varchar column with date data. Unfortunately the dates are in a whole slew of different formats.
2012-05-01
27/05/2012
07MAY2014
19/07/13
There may be others, but that's all I've encountered so far.
I need to squeeze these into a datetime column into another table, so I've been trying to select them as standard date-time values. At first, I thought that'd be easy:
UPDATE myTable
SET myDateColumn = CONVERT(DATETIME, myDateColumn, 103)
WHERE ISDATE(myDateColumn) = 0
But the trouble is that SQL Server treats dd/mm/yy and dd/mm/yyyy as separate formats. The former is code 3, and the latter is code 103. So whichever way I run that update, it chokes on the opposite format.
Is there any way I can select/update based on the date format, and get all these dates converted to a single valid DateTime format?
My guess is that you just have to try to differentiate between the different classes and handle each case in the appropriate way. Something like this:
declare #tab table (d varchar(20))
insert #tab values ('2012-05-01'),('27/05/2012'),('07MAY2014'),('19/07/13')
select
case
when isnumeric(left(d,4)) = 1 then cast(d as date)
when len(d) = 10 then convert(date, d, 103)
when len(d) = 8 then convert(date, d, 3)
when charindex('/',d) = 0 and isnumeric(d) = 0 then convert(date, d, 106)
end as [date]
from #tab
Output:
date
----------
2012-05-01
2012-05-27
2014-05-07
2013-07-19
It might not be that efficient, but I presume this is a one-off operation. I didn't write it as an update statement, but the query should be easy to adapt, and you should consider adding the converted date as a new proper datetime column if possible in my opinion.
Edit: here's the corresponding update statement:
update #tab
set d =
case
when isnumeric(left(d,4)) = 1 then cast(d as date)
when len(d) = 10 then convert(date, d, 103)
when len(d) = 8 then convert(date, d, 3)
when charindex('/',d) = 0 and isnumeric(d) = 0 then convert(date, d, 106)
end
from #tab
This is totally horrid, but it works with your example:
DECLARE #DodgyDates TABLE (
DateString VARCHAR(50));
INSERT INTO #DodgyDates VALUES ('2012-05-01');
INSERT INTO #DodgyDates VALUES ('27/05/2012');
INSERT INTO #DodgyDates VALUES ('07MAY2014');
INSERT INTO #DodgyDates VALUES ('19/07/13');
SELECT * FROM #DodgyDates;
--SELECT CONVERT(DATE, DateString) FROM #DodgyDates;--Fails
WITH DateDeconstruct AS (
SELECT
*,
CASE
WHEN DateString LIKE '____-__-__' THEN DateString
WHEN DateString LIKE '__/__/____' THEN RIGHT(DateString, 4) + '-' + SUBSTRING(DateString, 4, 2) + '-' + LEFT(DateString, 2)
WHEN DateString LIKE '__/__/__' THEN '20' + RIGHT(DateString, 2) + '-' + SUBSTRING(DateString, 4, 2) + '-' + LEFT(DateString, 2)
WHEN DateString LIKE '_________' THEN RIGHT(DateString, 4) + '-' + CONVERT(VARCHAR(2), DATEPART(MM, DateString)) + '-' + LEFT(DateString, 2)
END AS FixedString
FROM
#DodgyDates)
SELECT
DateString AS OriginalDate,
FixedString AS FixedDate,
CONVERT(DATE, FixedString) AS ConvertedDate
FROM
DateDeconstruct;
Results are:
OriginalDate FixedDate ConvertedDate
2012-05-01 2012-05-01 2012-05-01
27/05/2012 2012-05-27 2012-05-27
07MAY2014 2014-5-07 2014-05-07
19/07/13 2013-07-19 2013-07-19
In SQL Server 2012, you could use try_convert(). Otherwise, you could multiple updates:
UPDATE myTable
SET myDateColumn = CONVERT(DATETIME, myDateColumn, 103)
WHERE ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]';
UPDATE myTable
SET myDateColumn = CONVERT(DATETIME, myDateColumn, 3)
WHERE ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9]';
Note: the where clause will probably work here for the update. It does not work for a select. You may need to use a case as well:
UPDATE myTable
SET myDateColumn = (CASE WHEN ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]'
THEN CONVERT(DATETIME, myDateColumn, 103)
ELSE myDateColumn
END)
WHERE ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-0]'
Also, you are putting the values back in the same column so you are overwriting the original data -- and you have another implicit conversion back to a string I would strongly recommend that you add another column to the table with a datetime data type and put the correctly-typed value there.
For this first you can convert all the data into another format such as 110 the USA date fromat, and then further again update the whole table with the desired format.

If not <> NULL then "xxxField" equals '1'

I have a feeling this is a fairly simple one. I need to edit a line in the SELECT statement that looks to see if there is a value of NULL in a field. If there is a NULL value, I need the new column (not named) to display a '0' for that row. Where the row has data I need to display '1' in that row. Is there a way to do this without greatly modifying the logic I have? (Using SQL Server Management Studio)
Here's the code:
SELECT DISTINCT t.Name,
CONVERT(VARCHAR(10), t.DischargeDateTime, 120) AS DischargeDate,
t.PatientPortalEnabled,
t.Allergy,
CONVERT(VARCHAR(10), t.AllergyUpdateTime, 120) AS AllergyUpdate,
/*This is where I would like to put the logic if possible*/ <> NULL,
t.ElapseTimeForAllergyUpdateInMinutes,
t.OldValue,
t.NewValue,
t.ElapseTimeForAllergyUpdateInHours,
t.DischargeDateTime
Try this:
CASE WHEN MyField IS NULL THEN 0 ELSE 1 END
Here it is in your code:
SELECT DISTINCT t.Name,
CONVERT(VARCHAR(10), t.DischargeDateTime, 120) AS DischargeDate,
t.PatientPortalEnabled,
t.Allergy,
CONVERT(VARCHAR(10), t.AllergyUpdateTime, 120) AS AllergyUpdate,
CASE WHEN t.MyField IS NULL THEN 0 ELSE 1 END,
t.ElapseTimeForAllergyUpdateInMinutes,
t.OldValue,
t.NewValue,
t.ElapseTimeForAllergyUpdateInHours,
t.DischargeDateTime
You can do this using a CASE statement.
SELECT DISTINCT t.Name,
CONVERT(VARCHAR(10), t.DischargeDateTime, 120) AS DischargeDate,
t.PatientPortalEnabled,
t.Allergy,
CONVERT(VARCHAR(10), t.AllergyUpdateTime, 120) AS AllergyUpdate,
/*This is where I would like to put the logic if possible*/
CASE
WHEN t.MyField IS NULL THEN 0
ELSE 1
END AS MyNewField,
t.ElapseTimeForAllergyUpdateInMinutes,
t.OldValue,
t.NewValue,
t.ElapseTimeForAllergyUpdateInHours,
t.DischargeDateTime
Using XOR bitwise operator:
declare #x int = null
select isnull((#x ^ #x),-1)+1

SQL SERVER DATETIME FORMAT

Studying SQL Server there is something I am not sure of:
A datetime field with the value:
2012-02-26 09:34:00.000
If I select out of the table using:
CAST(dob2 AS VARCHAR(12) ) AS d1
It formats it as:
Feb 26 2012
What I am unsure of his how or why SQL Server formats DateTime like that. If you use datetime2 it does not - anyone know why?
The default date format depends on the language setting for the database server. You can also change it per session, like:
set language french
select cast(getdate() as varchar(50))
-->
févr 8 2013 9:45AM
try this:
select convert(varchar, dob2, 101)
select convert(varchar, dob2, 102)
select convert(varchar, dob2, 103)
select convert(varchar, dob2, 104)
select convert(varchar, dob2, 105)
select convert(varchar, dob2, 106)
select convert(varchar, dob2, 107)
select convert(varchar, dob2, 108)
select convert(varchar, dob2, 109)
select convert(varchar, dob2, 110)
select convert(varchar, dob2, 111)
select convert(varchar, dob2, 112)
select convert(varchar, dob2, 113)
refernces: http://msdn.microsoft.com/en-us/library/ms187928.aspx
http://www.w3schools.com/sql/func_convert.asp
Compatibility Supports Says that
Under compatibility level 110, the default style for CAST and CONVERT operations on time and datetime2 data types is always 121. If your query relies on the old behavior, use a compatibility level less than 110, or explicitly specify the 0 style in the affected query.
That means by default datetime2 is CAST as varchar to 121 format. For ex; col1 and col2 formats (below) are same (other than the 0s at the end)
SELECT CONVERT(varchar, GETDATE(), 121) col1,
CAST(convert(datetime2,GETDATE()) as varchar) col2,
CAST(GETDATE() as varchar) col3
SQL FIDDLE DEMO
--Results
COL1 | COL2 | COL3
2013-02-08 09:53:56.223 | 2013-02-08 09:53:56.2230000 | Feb 8 2013 9:53AM
FYI, if you use CONVERT instead of CAST you can use a third parameter to specify certain formats as listed here on MSDN
In MS SQL Server you can do:
SET DATEFORMAT ymd
case when isdate(inputdate) = 1
then convert(datetime, cast(inputdate,datetime2), 103)
else
case when isdate(inputdate) = 0
then convert(datetime, cast(inputdate,datetime2), 103)
This is my favorite use of 112 and 114
select (convert(varchar, getdate(), 112)+ replace(convert(varchar, getdate(), 114),':','')) as 'Getdate()
112 + 114 or YYYYMMDDHHMMSSMSS'
Result:
Getdate() 112 + 114 or YYYYMMDDHHMMSSMSS
20171016083349100
to change the date format by using sql syntax you should use this query
SELECT DATE_FORMAT(`<columnName>`, '%d/%m/%Y') FROM schemaname.tablename;
ex:-
for suppose i have a schema named as bugloo and the table name is tbl_company
and in this tbl_company i have a column all are in the date format %yy/%mm/%dd and column name is createdDate and the query should like this
SELECT DATE_FORMAT(`createdDate`, '%d/%m/%Y') FROM bugloo.tbl_company;
after running this query my output date would be converted to %dd/%mm/%yyyy

How to build this sql query

i want to find the records in sql
from say 25-08-2012 to 01-09-2012
and i want to group by date
here is my query
SELECT CONVERT(VARCHAR(10), date, 105) AS dt,
COUNT(id) AS cnt
FROM tablename
WHERE date BETWEEN CONVERT(DATETIME, '21-08-2012 00:00:00:000',103)
AND CONVERT(DATETIME, '01-09-2012 23:59:00:000' ,103)
GROUP BY CONVERT(VARCHAR(10), date, 105)
i am getting result as
dt cnt
01-09-2012 48
27-08-2012 1
28-08-2012 3
29-08-2012 11
30-08-2012 3
but expect it as
dt cnt
25-08-2012 0
26-08-2012 0
01-09-2012 48
27-08-2012 1
28-08-2012 3
29-08-2012 11
30-08-2012 3
How i can modify above query
i also tried with CASE but no luck
Many Thanks..
The reason you are missing these dates in result is that there's no data for them in your table, however, the following would insure you are getting all of the dates in specified range:
CREATE TABLE #tmp_dates ([date] datetime)
DECLARE #dt_start datetime, #dt_end datetime, #dt_dif int
SET #dt_start = CONVERT(DATETIME, '21-08-2012 00:00:00:000',103)
SET #dt_end = CONVERT(DATETIME, '01-09-2012 23:59:00:000' ,103)
SET #dt_dif = datediff(day,#dt_start,#dt_end)
WHILE #dt_dif >= 0 BEGIN
INSERT INTO #tmp_dates
SELECT dateadd(day,#dt_dif,#dt_start)
SET #dt_dif = #dt_dif - 1
END
SELECT CONVERT(VARCHAR(10), t2.[date], 101) AS dt, COUNT(t1.id) AS cnt
INTO #tmp_result
FROM tablename t1
RIGHT OUTER JOIN #tmp_dates t2
ON CONVERT(VARCHAR(10), t1.[date], 101) = CONVERT(VARCHAR(10), t2.[date], 101)
GROUP BY CONVERT(VARCHAR(10), t2.[date], 101)
ORDER BY CONVERT(DATETIME,CONVERT(VARCHAR(10), t2.[date], 101)) ASC /* DESC */
SELECT convert(VARCHAR(10),CONVERT(DATETIME,dt),105) as dt,cnt FROM #tmp_result
DROP TABLE #tmp_dates
DROP TABLE #tmp_result
Your query cannot be directly modified to return the data you want. To count the dates in question, there must be records in the target table actually having those dates; in your case, however, the dates are merely parameters in the query. As a result, there is no way to incorporate them into your result set.
You must create a secondary table that includes all the dates for which you want data, and then recharacterize your query as a left outer join from that date table to your target table. This will, in turn, give you the zero counts for the dates present in the "date" table, but absent from the target table.
How about using IsNull()? Let me know if this works.
SELECT CONVERT(VARCHAR(10), date, 105) AS dt,
ISNULL(COUNT(id),0) AS cnt
FROM tablename
WHERE date BETWEEN CONVERT(DATETIME, '21-08-2012 00:00:00:000',103)
AND CONVERT(DATETIME, '01-09-2012 23:59:00:000' ,103)
GROUP BY CONVERT(VARCHAR(10), date, 105)