Loosing the battle - Datediff working but I want to apply a condition - datediff

I know I'm gonna 'kick myself' when I see the answer but right now I can't see it.
SELECT [faxdate]
,DATEDIFF(day,
CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' + SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE), getdate()) AS vDiff
faxdate vDiff 20130704 62 20130705 61
20130705 61 20130708 58
Works great, but I want to be able to test the number of days Eg. records over 60 days.
When I add this :
WHERE (DATEDIFF(day,
CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' + SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE), getdate()) >60)
I get: Conversion failed when converting date and/or time from character string.
I have also tried this sql as a derived table and then tested vDiff ....i'm obviously not doing it right
any help would be appreciated
ttfn
Martyn
(Cornwall England and it's not raining .. result !)

Try
SELECT [faxdate],DAY(DATEDIFF(CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' +
SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE),
getdate())) AS vDiff
instead of using where, use having like below
HAVING vDiff > 60

Related

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.

Cumulative sum with conditions

I tried to get cumulative sums throught column week (and if is possible, then get result ordered by column Datum$ADTE) in my query:
select
A.Castka "Amount",
'Cashflow' as N,
A.Datum$DATE "Datum",
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"
from iGateCashflow A
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
In where clause are conditions, whichs will be edited througt external form.
I would like to get result like this (better without Amount column)
week N Amount Result
44 Cashflow 150 150
45 Cashflow 200 350
46 Cashflow 300 650
47 Cashflow 350 1000
I tried something like this, but I can't achieve my expected result:
select
sum(y.Amount),
Y.N,
Y.Week
from (
select
A.Castka "Amount",
'Cashflow' as N,
A.Datum$DATE "Datum",
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"
from iGateCashflow A
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
) X
join (
select
A.Castka "Amount",
'Cashflow' as N,
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"
from iGateCashflow A
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
) Y on Y.Week <= X.Week
group by
Y.N,
Y.Week
order by
Y.Week
I think there's more your question than what you showed. But use this as an idea (you'll need to add in WHERE conditions, etc)
SELECT *,
SUM(Amount) OVER (ORDER BY [week])
FROM iGateCashflow
Better to use OVER Clause to get Sum partition by Week and order by Date, please refer to
Over Clause
Maybe try something like this
select
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week",
sum(B.Castka) "Total amount"
from iGateCashflow A
inner join iGateCashflow B
on A.BusTransaction_ID = B.BusTransaction_ID
and A.Vyjasneno = B.Vyjasneno
and B.week <= A.week --> if week is a calculated field, include the calculation here for both 'week's
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
group by cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"

No Date Returned from Conversion

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

Converting/concatenating individual bytes from a VARCHAR into a BIGINT using T-SQL

Working between two database systems, I need to convert a VARCHAR identifier into a BIGINT. My VARCHAR is always of the form "###-XXX-XXX-###" where # is any digit, and X is any alpha-numeric character (e.g. "103-AF7-GGB-005"). The two ### entries are guaranteed to be below 256, so I want to store each of those in a single byte of the BIGINT (the first and last bytes respectively), with each of the 6 other characters stored as a byte each.
I've implemented this outside of the database, and it solves the problem I needed it to, but now I have the need to create the function in t-sql and I have not been able to figure out how to do this.
Thanks in advance for the help!
You could do this:
DECLARE #inp VARCHAR(100) = '223-ABC-DEF-234'
, #BITS BIGINT;
SELECT #BITS =
CASE
WHEN CONVERT(BIGINT, LEFT(#inp, 3)) > 127
THEN (CONVERT(BIGINT, LEFT(#inp, 3))-128) * POWER(CONVERT(BIGINT, 2), 56)
-9223372036854775808
ELSE CONVERT(BIGINT, LEFT(#inp, 3)) * POWER(CONVERT(BIGINT, 2), 56)
END
+ CONVERT(BIGINT, ASCII(substring(#inp, 5, 1))) * POWER(CONVERT(BIGINT, 2), 48)
+ CONVERT(BIGINT, ASCII(substring(#inp, 6, 1))) * POWER(CONVERT(BIGINT, 2), 40)
+ CONVERT(BIGINT, ASCII(substring(#inp, 7, 1))) * POWER(CONVERT(BIGINT, 2), 32)
+ CONVERT(BIGINT, ASCII(substring(#inp, 9, 1))) * POWER(CONVERT(BIGINT, 2), 24)
+ CONVERT(BIGINT, ASCII(substring(#inp, 10, 1))) * POWER(CONVERT(BIGINT, 2), 16)
+ CONVERT(BIGINT, ASCII(substring(#inp, 11, 1))) * POWER(CONVERT(BIGINT, 2), 8)
+ CONVERT(BIGINT, RIGHT(#INP, 3));
select CONVERT(binary(8), #bits);
-- Returns 0xDF414243444546EA
SELECT CONVERT(VARCHAR, CONVERT(INT, 0XDF))
+ '-' + CHAR(0X41)
+ CHAR(0X42)
+ CHAR(0X43)
+ '-' + CHAR(0X44)
+ CHAR(0X45)
+ CHAR(0X46)
+ '-' + CONVERT(VARCHAR, CONVERT(INT, 0XEA));
-- Returns 223-ABC-DEF-234: our original string
The big subtraction is to flip the sign bit. You're using all 64 bits if the first number is more than 127. Just multiplying by 2^56 will overflow the data type, since BIGINT is signed.

How to convert a Cursor into SELECT queries?

I am using SSRS 2008 and i have a stored proc which currently uses cursors to delete and add data, but even after I convert this to select queries, I am getting error:
Msg 102, Level 15, State 1, Line 39
Incorrect syntax near ')'.
Here was the original Cursor which worked:
OPEN PARTS
FETCH PARTS INTO #PART_NUM,
#PART_DESC
SET #PARTS_FETCH = ##FETCH_STATUS
WHILE #PARTS_FETCH = 0 BEGIN
SET #THE_DATE = dateadd("yy", -1, dateadd("m", -1, getdate()))
SET #END_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, getdate()) + 1, 0))
-- Get PL for part number
Delete from #tbl_PL
Insert #tbl_PL
SELECT FRUD.tblXref.product_code FROM FRUD.tblfieldOrderablePart INNER JOIN
FRUD.MAX_APPROVED ON FRUD.tblfieldOrderablePart.fop_no = FRUD.MAX_APPROVED.fop_no AND
FRUD.tblfieldOrderablePart.fop_revision = FRUD.MAX_APPROVED.MaxOffop_revision INNER JOIN
FRUD.tblXref ON FRUD.MAX_APPROVED.fop_no = FRUD.tblXref.fop_no AND
FRUD.MAX_APPROVED.MaxOffop_revision = FRUD.tblXref.fop_revision
WHERE (dbo.FORMAT_PART(FRUD.tblfieldOrderablePart.fop_no) = dbo.FORMAT_PART(#PART_NUM))
-- End Get PL
WHILE #THE_DATE <= #END_DATE BEGIN
SET #THE_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, #THE_DATE) + 1, 0))
-- Get census using PL
SELECT #ALL_TOTAL = SUM(TheSum) FROM (SELECT CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum, (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102)) as ThePeriod
FROM RELIABILITY.Census
WHERE RELIABILITY.Census.PL In (Select distinct * FROM #tbl_PL)
AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102) >=
DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0)) AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4)
+ '-' + RIGHT(Period, 2) + '-1', 102) <= #THE_DATE) UNION ALL SELECT CAST(Census AS DECIMAL(9,2)) AS TheSum, Period FROM [MANUAL].SMARTSOLVE_CENSUS WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL)))A
And here is my conversion to Select:
DECLARE #THE_DATE datetime,
#END_DATE datetime,
#THE_GOAL decimal(18,2),
#PART_NUM nvarchar(50),
#UNCHANGED_PART_NUM nvarchar(50),
#PART_DESC varchar(35),
#PARTS_FETCH int,
#NUM_FAILED int,
#AVG_CENSUS decimal(18,2),
#PL_VAR nvarchar(50),
#PL_FETCH int,
#PL_TOTAL decimal(9,2),
#ALL_TOTAL decimal(9,2)
--WHILE #PARTS_FETCH = 0 BEGIN
SET #THE_DATE = dateadd("yy", -1, dateadd("m", -1, getdate()))
SET #END_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, getdate()) + 1, 0))
--WHILE #THE_DATE <= #END_DATE BEGIN
SET #THE_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, #THE_DATE) + 1, 0))
-- Get census using PL
SELECT #ALL_TOTAL = SUM(TheSum) FROM
(SELECT CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum
from RELIABILITY.Census
WHERE RELIABILITY.Census.PL In (Select distinct * FROM #tbl_PL)
AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102) >=
DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0)) AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4)+ '-' + RIGHT(Period, 2) + '-1', 102) <= #THE_DATE)
UNION ALL
SELECT CAST(Census AS DECIMAL(9,2)) AS TheSum, Period
FROM [MANUAL].SMARTSOLVE_CENSUS
WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL))
))A
As Joel and Lamak pointed out you have an extra ) This is actually really easy to find if you use something like Instant SQL formatter This will give the error
)(11,3) expected token:Unknown
)(11,3) expected token:
It also formats the SQL as below which makes it a little easier to follow.
SELECT #ALL_TOTAL = SUM(thesum)
FROM (SELECT CAST(reliability.census.census AS DECIMAL(9, 2)) AS thesum
FROM reliability.census
WHERE reliability.census.pl IN (SELECT DISTINCT *
FROM #tbl_pl)
AND ( CONVERT(DATETIME, LEFT(CONVERT(CHAR, period), 4) + '-' +
RIGHT(
period, 2)
+
'-1'
, 102) >= Dateadd(mm, Datediff(mm, 0, #THE_DATE) - 5, 0) )
AND ( CONVERT(DATETIME, LEFT(CONVERT(CHAR, period), 4)+ '-' +
RIGHT(
period, 2) +
'-1',
102) <= #THE_DATE )
UNION ALL
SELECT CAST(census AS DECIMAL(9, 2)) AS thesum,
period
FROM [MANUAL].smartsolve_census
WHERE ( period >= Dateadd(mm, Datediff(mm, 0, #THE_DATE) - 5, 0)
AND period <= #THE_DATE )
AND ( pl IN (SELECT DISTINCT *
FROM #tbl_pl) ))a
Sounds like you have mis-matched parentheses, double check and make sure they all line up correctly. You have one more ")" at the end of that last select statement than you have ever being opened. That's a lot of nesting! Make sure everything matches up how you intended, or you may get unexpected results if your UNION gets applied at the wrong level or something.
If I'm reading your query correctly, you have two errors. The first is an extra ")" on the last line, it should be:
WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL))
) A
And, I think you also have more columns on your query after the UNION ALL, you are selecting CAST(Census AS DECIMAL(9,2)) AS TheSum, Period and on the first one you are selecting only one column: CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum