Convert Decode from Oracle to Case from MS SQL Server - sql-server

I have this line I am struggling with to convert a query from Oracle to SQL Server 2012. the following line is:
DECODE(SUM(DECODE(a.canceldate, NULL, 1,0)), 1, NULL, To_Date(MAX(TO_CHAR(a.canceldate,'yyyymmdd')), 'yyyymmdd')) dCancelDate,
As I inteprete is to convert it like:
case a.canceldate
(when sum(case a.canceldate when Null then 1 else 0 end))
when 1
then 0
else convert(datetime,a.canceldate)
end max(a.canceldate) as dCancelDate,
I will appreciate some assistant, my line is not correct for SQL Server 2012.

The decode formula is equivalent to
case sum(case when a.canceldate is null then 1 else 0 end) when 1 then null
else to_date( ... ) end dCancelDate, ...
One mistake I saw in your translation is that you have when sum(...) when 1. You can't have it both ways, it is either when sum(...) = 1 or sum(...) when 1. It may be the only mistake, I didn't look too hard.
What you have within the to_date() is horrible; are you converting dates to character strings, then take the max IN ALPHABETICAL ORDER and then translate back to date? Why? Perhaps just so you delete the time-of-day component? That is a lot easier done with trunc(max(a.canceldate)).

Related

ASCII Comparisons when Using SQL_Latin1_General_CP1_CI_AS

I ran the query below to see how strings would compare in SQL Server, since a different query based on comparison of fields with this type of data yielded different results than expected. I wasn't sure whether the angle bracket would be considered a lower value than a number (based on the ASCII table it would not, but wanted to check). As a result of the outcome, I've reviewed multiple posts regarding string comparison, collation and expected values and they all seem to reinforce that this should not be working this way. The collation on the database (as on the field that caused trouble) is SQL_Latin1_General_CP1_CI_AS.
SELECT ASCII('<') AS [<]
,ASCII('0') AS [0]
,CASE WHEN '<0.1' < '0.1' THEN 1 ELSE 0 END AS TEST1
,CASE WHEN '<' < '0' THEN 1 ELSE 0 END AS TEST2
,CASE WHEN ASCII('<') < ASCII('0') THEN 1 ELSE 0 END AS TEST3
Result:
< 0 TEST1 TEST2 TEST3
60 48 1 1 0
Any ideas to point me in the right direction would be very much appreciated!

Handle Null values without Case

Hi I had a Table called Details which contains column Day1 with datatype as Int.
Now if the Column Day1 contains any number then I want to display 100 else if it contains null I want to display null only.
Apart from writing below case statement is there any more simpler way to do it?:
Case when Day1=10 /*(Apart from 0 it can have any value including null)*/ then 100 else Day1
I had around 31 columns I dont want to write case for each and every column. Is there a better way to do this?
Certainly No, if you are thinking of using ISNULL() or COALESCE() function but you can modify your CASE expression to be like below
Case when Day1 > 0 or Day1 IS NULL then 100 else Day1
Hi you can check for NULL in the CASE-Statement:
SELECT CASE WHEN Day1 IS NULL THEN Day1 ELSE 100 END AS Day1 FROM Details
Well, I didn't exactly get what's your intention of writing such a query, but nevertheless, this case will do it.
CASE WHEN Day1 IS NULL THEN NULL ELSE 100 END
Since you say you want to check whether it is a number or not, ISNUMERIC comes to mind:
CASE WHEN ISNUMERIC(Day1) = 1 THEN 100 ELSE NULL END
, but I think simply writing
CASE WHEN Day1 IS NULL THEN NULL ELSE 100 END
or
IIF(ISNUMERIC(Day1) = 1, 100, NULL)
is more intuitive (see how you don't need a CASE in this case? :-))
If you are using SQL Server 2012 or newer:
IIF(Day1 IS NULL, NULL, 100)
or you can make a user-defined function to do the same thing even more concisely (works with all versions of SQL Server):
CREATE FUNCTION dbo.MyFunc(#Day int)
RETURNS int
RETURN (CASE WHEN #Day IS NOT NULL THEN 100 ELSE NULL END)
Usage:
SELECT MyFunc(Day1), MyFunc(Day2)

Error converting varchar to bigint in very peculiar situation

My intent is to retrieve all CLIENT_CODE converted to BigInt, to compare with a value passed as a parameter in the where clause from a 400 lines sql query. When execute the code below, I get the following error message:
message error 8114 from sql server: "Error converting varchar to
bigint".
Test Code:
select CASE when (len (CLIENT_CODE) > 2 and isNumeric(CLIENT_CODE) = 1)
then (CAST(SUBSTRING(TAB.CLIENT_CODE, 1, LEN(TAB.CLIENT_CODE)-1) AS BIGINT))
else CLIENT_CODE end from TABLE TAB
Code Nested:
--HUGE_SQL...
AND ((CASE when (len (CLIENT_CODE) > 2 and isNumeric(CLIENT_CODE) = 1)
then (CAST(SUBSTRING(TAB.CLIENT_CODE, 1, LEN(TAB.CLIENT_CODE)-1) AS BIGINT))
else CLIENT_CODE end) = #MyClient_Code)
--... HUGE_SQL
Our CLIENT_CODE is varchar(20), some have 0 characters, and some have letters, but almost every record is a number.
In my understanding, the case must be evaluated first, but it don't appear to be the case.
When i put the isNumeric(CLIENT_CODE) = 1 in the where clause, in test code, it works. My problem is that i can't do it in this particular case, because the fact it is already nested in the where clause from a huge sql query, and adding the isNumeric(CLIENT_CODE) = 1 there doesn't work, because it has a lot of other conditions.
Which is the best way to retrieve this data? Can someone figure it out how to do it?
(It will be very helpfull some kind of explanation of how is treated the functions vs case vs where)
Your Case expression Returns BIGINT in one case and else it return VARCHAR data type .
For Case expression, in each case the returned data type must be same.
Also instead of using ISNUMERIC() use following
select CASE
when (len (CLIENT_CODE) > 2 and CLIENT_CODE NOT LIKE '%[^0-9]%')
then (CAST(SUBSTRING(TAB.CLIENT_CODE, 1, LEN(TAB.CLIENT_CODE)-1) AS BIGINT))
end
from TABLE TAB
ISNUMERIC() returns true for values like 123a1 , 346g2 it considers it as raise to power stuff, therefore use NOT LIKE '%[^0-9]%' to get strings where only actual numeric values are present.

Converting text to Datetime in specific format

I need an expression which will convert a text (VARCHAR) column to a DATETIME if, and only if, it matches dd/MM/yyyy, d/MM/yyyy, dd/M/yyyy or d/M/yyyy. If it doesn't match then I want a NULL.
I have this...
CASE ISDATE([DateField])
WHEN 1 THEN CONVERT(DATETIME,[DateField],103)
ELSE NULL
END
However this fails for '15/04/76' for example - with a "Conversion failed when converting datetime from character string" error - whereas I would want it to return NULL
Example output
'1/6/1976' -> 1976-06-01
'01/06/1976' -> 1976-06-01
'13/06/2001' -> 2001-06-13
'06/13/2001' -> NULL
'13/06/76' -> NULL
Is there a way of forcing ISDATE to validate a given format?
The documentation seems to suggest so...
ISDATE is deterministic only if used with the CONVERT function, the
CONVERT style parameter is specified and style is not equal to 0, 100,
9, or 109.
But ISDATE only takes one argument, so how do I "use it with CONVERT function" if I am not doing so already?
You could do a nested case statement here. The first could check to see if you have a 10 character string 2 for day, 2 for month, 4 for year and 2 for separators = 10 characters.
SET DATEFORMAT DMY;
Case When DateField Like '%/%/[0-9][0-9][0-9][0-9]'
Then Case When IsDate(DateField) = 1
Then CONVERT(DATETIME,[DateField],103)
End
End
Revised: I changed the code to use a like search which forces there to be a /YYYY at the end of the string, and then does an IsDate check to allow for a single day and/or month.
Well, first off, why on earth are you storing datetime values in a varchar column? This is a cardinal sin for a variety of reasons, not the least of which is that you get no validation whatsoever that the data is (or is convertible to) a datetime. You should also consider validating the input, even if you leave the column as varchar, so you don't have such a wide variety of potential formats that you want to consider valid.
So here is one way, borrowing a bit from #G Mastros:
DECLARE #f TABLE(i INT, d VARCHAR(32));
INSERT #f VALUES
(1,'15/04/76'),
(2,'15/04/1976'),
(3,'1/3/1976'),
(4,'1/3/76'),
(5,'15/3/1976'),
(6,'22/22/22'),
(7,'Yesterday');
SET DATEFORMAT DMY;
SELECT i, d, d2 = CASE WHEN ISDATE(d) = 1
AND d LIKE '%/[0-9][0-9][0-9][0-9]'
THEN CONVERT(DATETIME, d, 103) END
FROM #f;
Results:
i d d2
- ---------- -----------------------
1 15/04/76 NULL
2 15/04/1976 1976-04-15 00:00:00.000
3 1/3/1976 1976-03-01 00:00:00.000
4 1/3/76 NULL
5 15/3/1976 1976-03-15 00:00:00.000
6 22/22/22 NULL
7 Yesterday NULL
PS this will be a great case for TRY_CONVERT in SQL Server 2012. It does exactly what you're asking - it tries to convert to the specified data type; if it can't, it returns NULL.
Thanks for the responses folks.
I've done it like this...
CASE ISDATE([DateField]) WHEN 1 THEN
CASE WHEN SUBSTRING([DateField],LEN([DateField])-4,1) = '/' THEN
CASE WHEN CHARINDEX('/',[DateField],LEN([DateField])-3)=0 THEN
CONVERT(datetime, [DateField] , 103)
END
END
END
which is pretty nasty business so would still appreciate something neater!
But this doesn't work either - it still errors on mm/dd/yyyy format dates!
Scrap that last comment - it does seem to work now? Probably something to do with SET DATEFORMAT

Conversion failed when converting the nvarchar to int

I have a field which is varchar and contains numbers and dates as strings. I want to update all numbers in this field that is greater than 720. I have attempted firstly to do a select but I get this error:
Conversion failed when converting the nvarchar value '16:00' to data type int.
This is my query:
select id, case(isnumeric([other08])) when 1 then [other08] else 0 end
from CER where sourcecode like 'ANE%' --and other08 > 720
It fails when I uncomment the last part.
I am trying to get all numerics greater than 720, but I can't do the comaprison. It also fails when casting and converting.
Thanks all for any help
You also need to perform the checks and conversion in the WHERE clause:
SELECT
id,
CASE WHEN isnumeric([other08]) = 1 THEN CAST([other08] AS INT) ELSE 0 END
FROM CER
WHERE sourcecode LIKE 'ANE%'
AND CASE WHEN isnumeric([other08]) = 1 THEN CAST([other08] AS INT) ELSE 0 END > 720
You need to use IsNumeric in your where clause, to avoid trying to compare strings to the number 720. Eg:
select id, case(isnumeric([other08])) when 1 then [other08] else 0 end
from CER
where sourcecode like 'ANE%' and ISNUMERIC(other08) = 1 and other08 > 720
EDIT
As #Abs pointed out, the above approach won't work. We can use a CTE to compute a reliable field to filter on, however:
WITH Data AS (
select id
, case WHEN isnumeric([other08]) THEN CAST([other08] AS int) else 0 end AS FilteredOther08
, CER.*
from CER
where sourcecode like 'ANE%'
)
SELECT *
FROM Data
WHERE [FilteredOther08] > 720

Resources