SQL Conditional Cast VARCHAR for FLOAT - sql

When I run the following query I get error "Cannot cast VARCHAR to FLOAT". The problem is some else on my team designed the DB a while back and put Milliseconds as varchar and sSometime the value isn't there so he put "NA" instead.
Now when I cast the value for Milliseconds to take the AVE(), "NA" cannot be casted. Is there a way to define default value for "NA", like:
IF a.Milliseconds == "NA"
0
ELSE
CAST(a.Milliseconds AS FLOAT)
SELECT
b.Date,
AVG(CAST(a.Milliseconds AS FLOAT)) AS Milliseconds,
FROM Fields a
INNER JOIN Cycles b
ON a.CyclesId = b.Id
GROUP BY b.Date
Sample Data
CyclesId | Milliseconds
1 | 24.1557
2 | 23.4886
3 | NA

Use a CASE statement around your value
SELECT
b.Date,
AVG(CAST(CASE WHEN a.Milliseconds = 'NA' THEN '0' ELSE a.Milliseconds END AS FLOAT)) AS Milliseconds,
FROM Fields a
INNER JOIN Cycles b
ON a.CyclesId = b.Id
GROUP BY b.Date
If you want the NA values excluded all together then you will do the following:
SELECT
b.Date,
AVG(CAST(a.Milliseconds AS FLOAT)) AS Milliseconds,
FROM Fields a
INNER JOIN Cycles b
ON a.CyclesId = b.Id
WHERE a.Milliseconds != 'NA'
GROUP BY b.Date
see SQL Fiddle with Demo

use CASE... for example...
SELECT
b.Date,
AVG(CAST( (case when a.Milliseconds = 'NA' then 0 else a.Milliseconds end) AS FLOAT)) AS Milliseconds,
FROM Fields a
INNER JOIN Cycles b
ON a.CyclesId = b.Id
GROUP BY b.Date

Related

Combining INSERT and CASE SQL Server Queries

Here are a couple of SQL queries that I am trying to either write as a single query or two queries. I have tried various possibilities that I could think of but non worked.
I have a blank table tbl_Z. I am trying to LEFT JOIN tbl_A and tbl_B and load the result into tbl_Z plus update the Status column in tbl_Z from tbl_A based on criteria in the 2 SQL statements shown here:
INSERT INTO tbl_Z
SELECT a.*
FROM tbl_A a
LEFT JOIN tbl_B b ON a.AccountNumber = b.AccountNumber
WHERE a.Period = '09/30/2021'
AND b.AccountNumber IS NULL
UPDATE Z
SET Status = (SELECT
f.ContractDate, f.BK_Date, f.Period,
CASE
WHEN ISNULL(f.ContractDate, '1/1/1900') < ISNULL(f.BK_Date, '1/1/1900') AND f.BK_Date < ISNULL(f.Period, '1/1/1900')
THEN 'Bankrupt.Attrit'
ELSE 'Attrit'
END AS Status
FROM
tbl_A f
WHERE
Period = '09/30/2021')
Any help will be greatly appreciated.
I don't know about fields name, just add fields name in select put the case statement in write order of fields.
INSERT INTO tbl_Z
SELECT -- please write your all tbl_A fields here and then place below case in write order of selection
,
CASE
WHEN ISNULL(f.ContractDate, '1/1/1900') < ISNULL(f.BK_Date, '1/1/1900')
AND f.BK_Date < ISNULL(f.Period, '1/1/1900')
THEN 'Bankrupt.Attrit'
ELSE 'Attrit'
END AS Status
FROM tbl_A a
LEFT JOIN tbl_B b ON a.AccountNumber = b.AccountNumber
WHERE a.Period = '09/30/2021'
AND b.AccountNumber IS NULL;

Postgresql work with null rows after joins

For example, we have next query:
select A.id, A.field > (case when A.cond1 then
(case when B.field is null then 0 else B.field end) else
(case when C.field is null then 0 else C.field end) end)
from A left join B on B.A_id = A.id left join C on C.A_id = A.id;
Is there way to simplify work with replacing null to 0?
Yes, with COALESCE:
COALESCE(column_that_might_be_null, 0)
It accepts multiple arguments and works left to right returning the first non null:
COALESCE(column_that_might_be_null, another_possible_null, third_maybe_null, 0)
Is the equivalent of
CASE
WHEN column_that_might_be_null IS NOT NULL THEN column_that_might_be_null
WHEN another_possible_null IS NOT NULL THEN another_possible_null
WHEN third_maybe_null IS NOT NULL THEN third_maybe_null
ELSE 0
END
And it is SQL standard so should work on all compliant databases
PG also supports ISNULL and IFNULL which work similarly but I don't usually recommend them over COALESCE because they don't exist in all databases/don't necessarily work equivalently and aren't as flexible because they only accept 2 arguments. For me this isn't enough to justify saving 2 characters.. (And if you forget about COALESCE, and you end up doing ISNULL(ISNULL(ISNULL(first, second), third), 0) the SQL is more messy)

LEFT JOIN with right table criteria

I would like to join table A and B with the following criteria to get the result table.
TABLE A is the Starting TIME
TABLE B consist of both TIME IN and TIME OUT
USER need to clock in (TIME IN), start machine (TIME START), clock out (TIME OUT)
TIME IN >= TIME START
TIME START >= TIME OUT
MAX TIME IN/OUT
DISTINCT Results based on ID
I tried left join but couldn't get the result that I want. I tried using CASE but the are lots of redundant result. Please advise.
SELECT a.ID as id,
GROUP_CONCAT(CASE
WHEN b.Code = 'In'
THEN b.Time
end) as `Time In`,
`TIME START`,
GROUP_CONCAT(CASE
WHEN b.Code = 'Out'
THEN b.Time
end) as `Time Out`
FROM `Table A` a
JOIN `Table B` b on a.ID = b.ID
WHERE 1
AND ((b.Code = 'In' && b.`TIME` <= a.`TIME START`) OR
(b.Code = 'Out' && b.`TIME` >= a.`TIME START`))
GROUP BY a.ID, a.`Time Start`
query doesn`t handle Code='In/Out' you need to split this explict
You can do this with a couple of LEFT JOINs:
SELECT
ts.ID,
MAX(ti.Time) AS Time,
MAX(ts.TimeStart) AS TimeStart,
MAX(tto.Time) AS TimeOut
FROM tableA ts
LEFT JOIN tableB ti ON ts.ID = ti.ID AND ti.Code IN ('IN','IN/OUT') -- "Time IN"
LEFT JOIN tableB tto ON ts.ID = tto.ID AND tto.Code IN ('Out','IN/OUT') -- "Time OUT"
GROUP BY ts.ID
ORDER BY ts.ID
Like Impaler mentioned, your description of IN/OUT and the desired result you provided don't seem to be in sync. The example above assumes IN/OUT is both IN and OUT. This will also give you the max TimeIn/TimeOut values if there are duplicate entries.
DB Fiddle (Postgres)
Try aggregating table B before the join:
WITH cte AS
( -- pivot into in/out time
SELECT
ID
,Max(CASE WHEN Code IN ('IN', 'IN/OUT') THEN Time END) AS TimeIn
,Max(CASE WHEN Code IN ('Out','IN/OUT') THEN Time END) AS TimeOut
FROM tableB
GROUP BY ID
)
SELECT
a.ID
,CASE WHEN TimeStart >= TimeIn THEN TimeIn END AS TimeIn
,TimeStart
,CASE WHEN TimeStart <= TimeOut THEN TimeIn END AS TimeIn
FROM tableA AS a
LEFT JOIN cte AS b
ON a.ID = b.ID

If else condition in MSSQL

Suppose I have serial number, test name and few other columns, i want to write a condition if TESTNAME is null for a particular serial number then set the TESTNAME to blank else perform inner join
SELECT
(A.PTNUMBER + '-' +A.SL_NO) AS ENUMBER,
D.ENGINEER AS REQ, D.DATETIME as "DATE",
(select Value
from DROPDOWN
where B.TEST_NAME=CONVERT(VARCHAR,DropdownID)) TESTNAME,
TABLE_NAME AS TABLETD
FROM INSPECTION D
INNER JOIN TABLEA A ON D.ENGID = CONVERT(VARCHAR,A.EN_ID)
INNER JOIN TABLEB B ON B.ENGID = CONVERT(VARCHAR,A.EN_ID)
INNER JOIN TABLEC C ON C.ENGID = CONVERT(VARCHAR,A.EN_ID)
not sure what you mean by set testname to blank but if you meant to be using a SELECT query then you can do like
select *,
case when TESTNAME is null and serial_number = some_value then '' end as TESTNAME
from mytable
You could combine a case expression and coalesce() along with your join to choose the value you want to return.
select serial_number, ...
,case when coalesce(testname,'') <> ''
then t2.testname
else coalesce(testname,'') end
from t
inner join t2
on ...
You can use isnull() or coalesce() in sql server to return a different value to replace null.
select isnull(testname,'')
or
select coalesce(testname,'')
The main difference between the two is that coalesce() can support more than 2 parameters, and it selects the first one that is not null. More differences between the two are answered here.
select coalesce(testname,testname2,'')
coalesce() is also standard ANSI sql, so you will find it in most RDBMS. isnull() is specific to sql server.
Reference:
isnull() - msdn
coalesce() - msdn
SELECT (A.PTNUMBER + '-' + A.SL_NO) AS ENUMBER,
D.ENGINEER AS REQ,
D.DATETIME as "DATE",
case
when SerialNo = xxx and TESTNAME is null then ''
else (select Value from DROPDOWN where B.TEST_NAME = CONVERT(VARCHAR, DropdownID))
end AS TESTNAME,
TABLE_NAME AS TABLETD
FROM INSPECTION D
INNER JOIN TABLEA A ON D.ENGID = CONVERT(VARCHAR, A.EN_ID)
INNER JOIN TABLEB B ON B.ENGID = CONVERT(VARCHAR, A.EN_ID)
INNER JOIN TABLEC C ON C.ENGID = CONVERT(VARCHAR, A.EN_ID);

How do you handle NULLs in a DATEDIFF comparison?

I have to compare 2 separate columns to come up with the most recent date between them. I am using DATEDIFF(minute, date1, date2) to compare them, however, in some records the date is Null, which returns a null result and messes up the CASE.
Is there a way around this, or a way to predetermine which date is null up front?
(psudocode)
UPDATE TABLE
SET NAME = p.name,
NEW_DATE = CASE WHEN DATEDIFF(minute,d.date1,d.date2) <= 0 THEN d.date
ELSE d.date2
END
FROM TABLE2 d
INNER JOIN TABLE3 p
ON d.ACCTNUM = p.ACCTNUM
You can just add extra logic into your CASE:
UPDATE TABLE
SET NAME = p.name,
NEW_DATE = CASE
WHEN d.date1 IS NULL THEN -- somewhat
WHEN d.date2 IS NULL THEN -- somewhat
WHEN DATEDIFF(minute,d.date1,d.date2) <= 0 THEN d.date
ELSE d.date2
END
FROM TABLE2 d
INNER JOIN TABLE3 p
ON d.ACCTNUM = p.ACCTNUM
I would use ISNULL.
UPDATE TABLE
SET NAME = p.name,
NEW_DATE = CASE WHEN ISNULL(DATEDIFF(minute,d.date1,d.date2), 0) <= 0 THEN d.date
ELSE d.date2
END
FROM TABLE2 d
INNER JOIN TABLE3 p
ON d.ACCTNUM = p.ACCTNUM
or maybe
ISNULL(DATEDIFF(minute,d.date1,d.date2), 1)
if you want to handle the null values the other way around.
You can try some think like this. You can use Is Null to check null.
UPDATE TABLE
SET NAME = p.name,
NEW_DATE = CASE Case When date2 Is Null Then GetDate()
Case When date1 Is Null Then GetDate()
WHEN DATEDIFF(minute,d.date1,d.date2) <= 0 THEN d.date
ELSE d.date2
END
FROM TABLE2 d
INNER JOIN TABLE3 p
ON d.ACCTNUM = p.ACCTNUM
Microsoft's ISNULL() function is used to specify how we want to treat
NULL values.
In this case we want NULL values to be zero.
Below, if "UnitsOnOrder" is NULL it will not harm the calculation,
because ISNULL() returns a zero if the value is NULL:
SQL Server / MS Access
SELECT ProductName,UnitPrice*(UnitsInStock+ISNULL(UnitsOnOrder,0)) FROM Products
SQL NULL Functions
This should give you what you want with minimal processing required.
UPDATE TABLE
SET NAME = p.name,
NEW_DATE = CASE WHEN COALESCE(date1, date2)>COALESCE(date2, date1)
THEN COALESCE(date1, date2)
ELSE COALESCE(date2, date1)
END
FROM TABLE2 d
INNER JOIN TABLE3 p
ON d.ACCTNUM = p.ACCTNUM
WHERE NOT (date1 is null and date2 is null);
I personally use this:
IIF([yourvariable] is null, expression_when_true, expression_when_false)
This actually works well if you have more complex datatypes like DATE. I've looked for the solution also and lots of people asked how to substract null date or why simple 0000-00-00 doesn't work. The IIF can avoid substraction when minuend or subtrahend is null.
Example:
IIF([ReturnDate] is null,
datediff(day,[BookDate],getdate())*CostPerDay,
datediff(day,[BookDate],[ReturnDate])*CostPerDay)