No Date Returned from Conversion - tsql

There are values there for the 3 fields that make up the date here, but I get null back..so something is wrong with my syntax. I also want just the date (no time) `
case when isdate(CAST(someTable.DATE_MM as varchar(8)) + CAST(someTable.DATE_DD as varchar(8)) + CAST (someTable.DATE_YY as varchar(8))) = 1
then convert(date,CAST(someTable.DATE_MM as varchar(8)) + '/' + CAST(someTable.DATE_DD as varchar(8)) + '/' + CAST (someTable.DATE_YY as varchar(8))) else null end as BirthDate,
that's in my select statement and it's giving me NULL for the data. The values for those 3 fields are:
DATE_MM: 3
DATE_DD: 4
DATE_YY: 1959
the data type behind those 3 fields is int

You merge 3 varchar values together, it will return a varchar, therefore your isdate will return false and your case will return the null value from the else clause.

You could do it with dateadd instead.
select dateadd(day, DATE_DD - 1,
dateadd(month, DATE_MM - 1,
dateadd(year, DATE_YY - 1900, 0))) as BirthDate
from someTable

Related

How do I use a calculated value within a DATEFROMPARTS in SQL

I need a calculated month value within DATEFROMPARTS function. The month has to be seven month prior to CURRENT_TIMESTAMP month.
This is what I tried:
DATEFROMPARTS(Year(CURRENT_TIMESTAMP), Month(CURRENT_TIMESTAMP)-7, 1) as SevenMoAgo;
I will eventually use this in the following expression where '12-01-2018' is:
where RECORDED_SERVICE_STARTTIME > ='12-01-2018'
I later used
declare #CurMo AS INT;
declare #MonPri7 AS INT;
set #CurMo = Month(CURRENT_TIMESTAMP);
set #MonPri7 = (#CurMo -7);
Datefromparts(Year(CURRENT_TIMESTAMP), #MonPri7, 1) as SevenMoAgo;
This also did not work.
I get the following error message:
"Cannot construct data type date, some of the arguments have values which are not valid."
For the second code I get:
Msg 102, Level 15, State 1, Line 8
Incorrect syntax near 'Datefromparts'.
Try this...
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - 7, 0)
Let me explain. First off, we need to understand that SQL Server interprets 0 as 1900-01-01 as shown by the following DATEPART functions.
SELECT DATEPART(YEAR, 0) AS Year
, DATEPART(MONTH, 0) AS Month
, DATEPART(DAY, 0) AS Day;
Which returns...
Year Month Day
----------- ----------- -----------
1900 1 1
Therefore, my SQL could be rewritten as...
SELECT DATEADD(MONTH, DATEDIFF(MONTH, '1900-01-01', CURRENT_TIMESTAMP) - 7, '1900-01-01')
Now perhaps it is a little easier to see what is going on here. The DATEDIFF function returns the number number of months between 1900-01-01 and today (CURRENT_TIMESTAMP) which is 1434.
SELECT DATEADD(MONTH, 1434 - 7, '1900-01-01')
Then we subtract 7 from 1434 which is 1427 and add that many months back to 1900-01-01.
SELECT DATEADD(MONTH, 1427, '1900-01-01')
Which yields 2018-12-01.
The reason is #MonPri7 is equal to ZERO when you say (#CurMo -7)
There are many different ways to calculate it, but if you want to fix your logic, you should use this:
declare #CurMo AS INT;
declare #MonPri7 AS INT;
set #CurMo = Month(CURRENT_TIMESTAMP);
set #MonPri7 = (#CurMo -7);
declare #Y int = Year(CURRENT_TIMESTAMP) -- <-- This is new variable
-- if 7 months ago is ZERO then you should go back to prev year December
if #MonPri7 = 0
begin
set #MonPri7 = 12
set #Y = #Y - 1
end
Edit:
declare #SevenMonthsAgo datetime;
select #SevenMonthsAgo = Datefromparts(#Y, #MonPri7, 1);
SELECT yourfields
FROM yourtable
where RECORDED_SERVICE_STARTTIME > = '01-01-2019' and
RECORDED_SERVICE_STARTTIME > = #SevenMonthsAgo

DAX counts rows between 2 dates

DECLARE #lower INT = 1
,#upper INT = 6
,#randnum INT
,#date DATE = getdate()
,#endofcurrentmonth DATE
,#loopdate DATE
,#loop INT
,#loopmax INT
,#innerloop INT
,#innerloopmax INT
,#value DATE
IF object_id('tempdb..#tmp_DateRange') IS NOT NULL
DROP TABLE #tmp_DateRange
CREATE TABLE #tmp_DateRange (
ID INT identity(1, 1) PRIMARY KEY NOT NULL
,[Date] DATE
)
IF object_id('tempdb..#tmp_RandomData') IS NOT NULL
DROP TABLE #tmp_RandomData
CREATE TABLE #tmp_RandomData (
ID INT identity(1, 1) PRIMARY KEY NOT NULL
,[BidDateWon] DATE
,[BidWon] BIT
)
SELECT #endofcurrentmonth = dateadd(mm, datediff(MM, 0, dateadd(MM, 1, #date)), 0) - 1
SELECT #loopdate = dateadd(mm, - 9, dateadd(dd, 1 - datepart(dd, #date), #date))
WHILE #loopdate <= #endofcurrentmonth
BEGIN
INSERT INTO #tmp_DateRange ([Date])
VALUES (#loopdate)
SET #loopdate = dateadd(dd, 1, #loopdate)
END
SELECT #loop = 0
,#loopmax = max(ID)
FROM #tmp_DateRange
WHILE #loop < #loopmax
BEGIN
SELECT #randnum = round(((#upper - #lower - 1) * rand() + #lower), 0)
SET #loop = #loop + 1
SET #innerloopmax = #randnum
SET #innerloop = 0
IF #randnum % 2 = 0
BEGIN
SET #value = (
SELECT [date]
FROM #tmp_DateRange
WHERE ID = #loop
)
END
ELSE
BEGIN
SET #value = NULL
END
WHILE #innerloop <= #innerloopmax
BEGIN
SET #innerloop = #innerloop + 1
INSERT INTO #tmp_RandomData (BidDateWon)
VALUES (#value)
END
END
UPDATE #tmp_RandomData
SET BidWon = 1
WHERE BidDateWon IS NOT NULL
SELECT *
FROM #tmp_RandomData
=CALCULATE(COUNTROWS(Fact_SalesSummaries),
DATESINPERIOD(Fact_SalesSummaries[BidWonDate],
LASTDATE(Fact_SalesSummaries[BidWonDate]),
-3, MONTH),
Fact_SalesSummaries[BidWonDate] <> BLANK())
I have tried search and different ways to counts rows that have dates between 2 different dates it calculates the rows as 1 and not more than that in the formula.
This is meant to be a rolling 3-month count of records from date back 3 months to be able to calculate an average with a count of all records.
Example in SQL would look like this.
select MonthBlended, yearblended, BidWonDate, BidWonFlag,
(select count(*) from Fact_SalesSummaries
where convert(date, cast(MonthBlended as varchar(2))+ '/01/' + cast(YearBlended as varchar(4)), 101) between
dateadd(mm, -3, convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101))
and convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101)
and BidWonDate is not null
) as CountWONPrior3Month,
(select count(*) from Fact_SalesSummaries
where convert(date, cast(MonthBlended as varchar(2))+ '/01/' + cast(YearBlended as varchar(4)), 101) between
dateadd(mm, -3, convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101))
and convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101)
) as CountALLPrior3Month
from Fact_SalesSummaries t1
BidWonDate BidWon CountWonPrior3Month CountAllPrior3Month
----------------------- ------ ------------------- -------------------
2014-07-17 00:00:00.000 1 618 1048
2014-07-17 00:00:00.000 1 618 1048
2014-07-17 00:00:00.000 1 618 1048
2014-07-17 00:00:00.000 1 618 1048
NULL 0 618 1048
NULL 0 618 1048
NULL 0 618 1048
NULL 0 618 1048
2014-07-17 00:00:00.000 1 618 1048
NULL 0 618 1048
NULL 0 618 1048
2014-07-11 00:00:00.000 1 618 1048
Well trying this in a measure does work but does not calculate correctly any help would be greatly appreciated.
I included a sql script that will give you a random data sample that will match the data I have. Run the script and it will generate a random dates or nulls that you can run the dax expression against. Thanks for any help.
I'm new to DAX and PowerBI,
as i've understood the calculate function, i think your second parameter is what's causing u the error, the second param must be a filter, you are not fitering anything in your case, you are just returning a range of dates,
i'm really trying to be helful even know i might be getting it wrong, anyway wouldnt hurt if you try it :D
Counting the number of records from the current date going back 3 months can be done with the following measure.
enumerator =
CALCULATE (
COUNTROWS ( Fact_SalesSummaries ),
DATESINPERIOD (
'Fact_SalesSummaries'[BidDateWon],
LASTDATE ( 'Fact_SalesSummaries'[BidDateWon] ),
3,
MONTH
),
Fact_SalesSummaries[BidDateWon] <> BLANK ()
)
The fact your lost bids dont have dates makes it difficult to get this accurate, because you have to rely on the ordinal (and hopefully contiguous) numbering of the ID's to create the denominator.
denominator =
CALCULATE (
MAX ( Fact_SalesSummaries[ID] ) - MIN ( Fact_SalesSummaries[ID] )
+ 1,
DATESINPERIOD (
'Fact_SalesSummaries'[BidDateWon],
LASTDATE ( 'Fact_SalesSummaries'[BidDateWon] ),
-3,
MONTH
)
)
If you had dates in the rows where the bidwon=false, you could use the same calclation as the enumerator, just removing the last filter.

How to see value of a char column sorted as I need

The table name is Date , and one of it's column's name is MonthOfYear (for jan the column value is 1 , for feb it is 2 , for march : 3 ... )and the other column is MonthName : this column contains the name of month ( jan , feb , march ..)
I need to see the result sorted ( jan be the first col , then feb , then march , then ...)
I updated the MonthName like this but it didn't work :
update Date
set [monthname] = cast(monthofyear as nvarchar(3)) + ' ' + rtrim(ltrim([monthname]))
You cannot get what you want sort on a char column
As a char 12 will sort before 2
You need to search on an integer column for 12 to sort before 2
So sort on MonthOfYear
Order By MonthOfYear
I don't know all your column names, but you don't want to change the data in the MonthName column.
Have you tried:
SELECT Year, MonthName
FROM Date
ORDER BY Year, MonthOfYear
To order by a varchar column you can put a 0 at the front of the single digit numbers.
Here's an example that shows how you can do it:
declare #t table (StringNumber varchar(3))
insert into #t (StringNumber)
select '9' union
select '10' union
select '11'
select StringNumber
from #t
order by StringNumber
select StringNumber, right('0' + StringNumber, 2) as OrderByStringNumber
from #t
order by right('0' + StringNumber, 2)

SQL Server 2008 R2 - convert all datetime parts (as ints) into a datetime column

I have a table that has the datetime pieces (year, month, day, hour, minute, second, millisecond) stored as integers. I'd like to concatenate them into a single datetime column.
I've tried various approaches but none work - there seems to be no simple way to put these items together?
You can convert each part to a varchar and concatenate them together in the format of an ISO datetime string. Then use Convert to convert the string to a DateTime.
Here is an example. You would need to replace each hard coded integer with the name of the column from your table.
SELECT CONVERT(DATETIME, CAST(2016 AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(8 AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(13 AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(16 AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(32 AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(07 AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(64 AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable
Or with column names (assumed)
SELECT CONVERT(DATETIME, CAST(yt.Year AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(yt.Month AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(yt.Day AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(yt.Hours AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(yt.Minutes AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(yt.Seconds AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(yt.Milliseconds AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable yt
One more note. Microsoft recommends that you use DateTime2 instead of DateTime to persist date time values starting with Sql Server 2008 (which you tagged in your question).
Prior to sql server 2012, you can use a series of nested DATEADD() functions to mimic DATETIMEFROMPARTS() function
Create and populate sample data (In your next question, please save us this step)
DECLARE #T as table
(
cYear int,
cMonth int,
cDay int,
cHour int,
cMinute int,
cSecond int,
cMillisecond int
)
INSERT INTO #T VALUES(2016, 6, 22, 16, 34, 25, 3)
The query:
SELECT *,
DATEADD(MILLISECOND, cMillisecond,
DATEADD(SECOND, cSecond,
DATEADD(MINUTE, cMinute,
DATEADD(HOUR, cHour,
DATEADD(DAY, cDay -1,
DATEADD(MONTH, cMonth - 1,
DATEADD(YEAR, cYear - 2000, '2000-01-01')
)
)
)
)
)
) As TheDate
FROM #T
Results:
cYear cMonth cDay cHour cMinute cSecond cMillisecond TheDate
----- ------ ---- ----- ------- ------- ------------- -----------------------
2016 6 22 16 34 25 3 2016-06-22 16:34:25.003
Note that the base date I'm using is January 1st 2000, therefor you need to subtract 2000 from the year, 1 from the month and 1 from the days.

Most Performant Way to Convert DateTime to Int Format

I need to convert Datetime fields to a specifically formatted INT type. For example, I want
2000-01-01 00:00:00.000 to convert to 20010101.
What is the most performant way to make that conversion for comparison in a query?
Something like:
DATEPART(year, orderdate) * 10000 + DATEPART(month, orderdate) * 100 +
DATEPART(day, orderdate)
or
cast(convert(char(8), orderdate, 112) as int)
What's the most performant way to do this?
Your example of cast(convert(char(8), orderdate, 112) as int) seems fine to me. It quickly gets the date down to the format you need and converted to an int.
From an execution plan standpoint, there seems to be no difference between the two.
You can try with TSQL builtin functions.
It's not .NET tick compatible but it's still FAST sortable and you can pick your GRANULARITY on demand:
SELECT setup.DateToINT(GETDATE(), 4) -- will output 2019 for 2019-06-06 12:00.456
SELECT setup.DateToINT(GETDATE(), 6) -- will output 201906 for 2019-06-06 12:00.456
SELECT setup.DateToINT(GETDATE(), 20) -- will output 20190606120045660 for 2019-05-05 12:00.456
CREATE FUNCTION setup.DateToINT(#datetime DATETIME, #length int)
RETURNS
BIGINT WITH SCHEMABINDING AS
BEGIN
RETURN CONVERT(BIGINT,
SUBSTRING(
REPLACE(REPLACE(
REPLACE(REPLACE(
CONVERT(CHAR(25), GETDATE(), 121)
,'-','')
,':','')
,' ','')
,'.','')
,0
,#length+1)
)
END
GO
Is this what you need
SELECT REPLACE(CONVERT(VARCHAR(10),'2010-01-01 00:00:00.000',101),'-','')
When you pass '2010-01-01 00:00:00.000' directly in your code, the SELECT statement looks at it as a string and not a datetime data type. Its not the same as selecting a datetime field directly.
There is no need to do outer CAST because SQL Server will do implicit conversion, here is a proof.
DECLARE #t DATETIME = '2010-01-10 00:00:00.000',#u INT
SELECT #u = CONVERT(CHAR(8), #t, 112)
IF ISNUMERIC(#u) = 1
PRINT 'Integer'