SQL: Can I negate a condition in a where clause? - sql

I want to check if a boolean is true, then decide in the WHERE clause what condition to use.
Say the boolean variable is #checkbool:
SELECT *
FROM TableA A
WHERE
--if #checkbool is true, run this
A.Id = 123
--if #checkbool is false, run this
A.Id <> 123
Is there a way to negate a condition? Like in C++ you can do if !(condition).
If not, what is the best way to solve this problem?
Thank you!

SQL's equivalent of ! in C is NOT. However, in your case you want something else: you need to build a condition that decides between the two choices based on the value of #checkbool, like this:
SELECT *
FROM TableA A
WHERE ( (#checkbool) AND (A.Id = 123))
OR ((NOT #checkbool) AND (A.Id <> 123))

Here is one solution:
IF #Checkbool = 1
SELECT * FROM Table A WHERE A.Id = 123
ELSE
SELECT * FROM Table A WHERE A.Id <> 123
Here is another using just the WHERE Clause:
SELECT *
FROM Table A
WHERE
(#Checkbool = 1 AND A.Id = 123)
OR
(#Checkbool = 0 AND A.Id <> 123)
Everything you put in the where clause needs to be in the form of an expression. Thus, the solution in this case is to write the condition in the form of an expression.
Hope this helps. :)

select *
from TableA A
where
(#checkbool = 1 and A.Id = 123) or
(#checkbool = 0 and A.Id <> 123)

If checkbool is a coumn, then something like this will do.(Not in proper SQL syntax)
WHERE (A.ID=123 AND A.checkbool=TRUE) OR (A.ID!=123 AND A.checkbool=TRUE)
If checkbool is not a cloumn, replace A.checkbool with value of checkbool.
here is the correct SQL
WHERE ((checkbool) AND (A.Id = 123))OR ((NOT checkbool) AND (A.Id <> 123))

You can use IN clausule or even the != operator, like:
A.Id NOT IN (123,x,y,z);
or
A.Id != 123;

Related

Avoid divide by zero with an IF SQL

I have this query:
SELECT sum((a.cant*b.cost)/b.cant) AS sum1
FROM
(SELECT partNo,cant
FROM table1 WHERE id=1) AS a,
(SELECT color,cost,cant
FROM table2 WHERE color in
(SELECT partNo FROM table1 WHERE id=1)) AS b
WHERE a.partNo=b.color
The problem is that sometimes b.cant will return 0, and when I do this part: SELECT sum((a.cant*b.cost)/b.cant) AS sum1 it will return a divide by zero error message, I was thinking on doing something like this:
SELECT IF (b.cant=0,0,sum((a.cant*b.cost)/b.cant)) AS sum1
Meaning that if b.cant equals zero then I want to return a 0 as final result and stop doing the division, but if it is not equal 0 then I will do the division, in my head this was the solution but is giving me an error.
Is there any other way to avoid doing the division and just return 0 if the divisor is 0?
You should fix your JOIN syntax and simplify the query:
SELECT SUM(a.cant*b.cost) / NULLIF(b.cant, 0) AS sum1
FROM table1 a JOIN
table2 b
ON a.partNo = b.color AND
a.id = b.id
WHERE a.id = 1;
It is rather suspicious that the join condition is between "partno" and "color", but that is how you have phrased it in your query. I wouldn't be surprised if that were an error.
The answer to your specific question is NULLIF(). But you should also learn how to write clearer SQL code. In particular, never use commas in the FROM clause. Learn to use proper, explicit, standard, readable JOIN syntax.
You should use JOIN instead of selecting columns using select statement. to avoid 0 you should use case expression as following
select
sum((a.cant*b.cost)/b.can) as sum1
from
(
select
a.partNo,
a.cant,
b.color,
b.cost,
(case when b.cant = 0 then 1 else b.cant) as b.cant
from table1 a
join table2 b
on a.partNo = b.color
where a.id = 1
) subq
You can use NULLIF() to return NULL when b.cant is 0:
SUM(a.cant * b.cost / NULLIF(b.cant, 0))
If there is a case that the final sum returns NULL but you want to see 0 then also use COALESCE():
COALESCE(SUM(a.cant * b.cost / NULLIF(b.cant, 0)), 0)
In terms of business, you can judge that b.cant equals zero, if b.cant equals zero then you can do the default.

SQL Filling In Values From A Second Table

I came up with this query to fill in a missing field from a second table using a subquery.
I can not modify the original table
SELECT
CASE WHEN original.target_field IS NULL THEN
(SELECT fill_in.target_field FROM second.table fill_in
WHERE original.id = fill_in.id)
ELSE
original.target_field END AS myField
FROM
primary.table original
I was wondering if I was missing something and if there was a more performant way to do this?
You could use LEFT JOIN and COALESCE instead of correlated subquery:
SELECT COALESCE(original.target_field,fill_in.target_field) AS myField
FROM primary.table original
LEFT JOIN second.table fill_in
ON original.id = fill_in.id
It is always worth testing different methods. But your query should be fine with an appropriate index.
I would write it as:
SELECT (CASE WHEN o.target_field IS NULL
THEN (SELECT f.target_field
FROM second.table f
WHERE o.id = f.id
)
ELSE o.target_field
END) AS myField
FROM primary.table o;
You want an index on second.table(id, target_field). You would want the same index for the LEFT JOIN version.

Translation of a character to another SQL Server

I want to translate a character from A - B but also in the same query I want to translate B - C if is found on a list. Let's say we have word "Apple" that gets translated to "Orange" but "Orange" it is also on the list and it gets translated to "Coconut", so the final result would be "Coconut". Is this possible ?. I do not want to use a cursor but i just can't find the answer..
update tableA
set Value = b.TargetValue
from tableA a
join
tableB b on b.SourceValue = a.Value
from my TableA i have let's say a list of fruits for this example i just have the fruit "Apple" on tableA but in tableB i have a translation for that word to "Orange", but also in the same tableB i have a translation for "Orange" to "Coconut" so i would expect to have as final result "Coconut". Does that help? it's my first time sorry if i didn't explain well.
EDIT
I have created a function for this. Hope it helps someone else with the same problem.
CREATE FUNCTION [dbo].[FunctionName]
(
#sourceValue varchar(11)
)
RETURNS varchar(11)
AS
BEGIN
declare #targetId varchar(11) = (select TargetID from tableWithValues where
SourceID = #sourceValue)
if #targetId is not null and #targetId <> #sourceValue
begin
set #targetId = dbo.FunctionName(#targetId)
end
else
begin
return #sourceValue
end
return #targetId
end
I would suggest you get a final dataset by joining both fruit tables, so when you get your final fruit just join that dataset(cte or temp table) with the table you want to update.
Hope this approach helps you solve the problem.
I don't think that there is general solution for this, but there is a work-around if there are reasonable limits to the number of substitutions.
For example, the A => B => C you describe has two levels of substitution. If the max number of levels is e.g. 5 you can code like this:
update tableA
set Value = case when b5.TargetValue is not null then b5.targetValue
else when b4.TargetValue is not null then b4.TargetValue
else when b3.TargetValue is not null then b3.TargetValue
else when b2.TargetValue is not null then b2.TargetValue
else when b1.TargetValue is not null then b1.TargetValue
else b0.TargetValue end case
from tableA a
join
tableB b0 on b0.SourceValue = a.Value
left outer join tableB b1 -- outer join for no sub
on b1.SourceValue = b0.TargetValue
left outer join tableB b1
on b2.SourceValue = b1.TargetValue
left outer join tableB b1
on b3.SourceValue = b2.TargetValue
left outer join tableB b1
on b4.SourceValue = b3.TargetValue
left outer join tableB b1
on b5.SourceValue = b4.TargetValue
Here, 5 levels are supported: A =>B =>C =>D =>E =>F. If you have a situation where 6 levels are needed (e.g F => G) then it won't happen, and the result will be F.
Note that the order of the when bx.TargetValue is not null statements is important.

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);

update multiple rows with joins

I have this query in postgresql:
select *
from A s
join B m on (s.id=m.id)
where m.key=4 and s.ran=some_input_from_user
This gives me all the rows that I need to update.
I want to set A.value to be 90 for all these rows.
It doesn't look like a standart update query
if I do...
Update A set value=90 where.....
then I can't do the join.
any ideas how to do it?
This is the basic update syntax for PostgreSQL where you are updating based on a join to another table:
update A s
set
value = 90
from B m
where
s.id = m.id and
m.key = 4 and
s.ran = some_input_from_user
The trick is you never use the alias in the lvalue for the set commands. In other words, value = 90 is not s.value = 90. It seems minor, but I'm pretty sure it will prevent your query from working. The rationale is if you are updating table A (alias s) then any fields you are updating are, de-facto, from table A -- no need to alias them, and to allow aliases would almost imply you could update something other than A with this statement, which you cannot.
You can definitely use them in the rvalues, so this would certainly be okay (if it were your desire to update A based on B):
update A s
set
value = m.salary * s.commission
from B m
where
s.id = m.id and
(s.value is null or
s.value != m.salary * s.commission)
Here is the query:
update a set value = 90
where exists (
select 1 from b
where a.id = b.id and b.key=4
and a.ran=some_input_from_user);
The above query will eliminate the requirement of reading table a twice.
Also you can use this query:
update a set value = 90
where a.id in
(select b.id from b
where a.id = b.id and b.key = 4
and a.ran=some_input_from_user);
TRY THIS
UPDATE A
SET A.VALUE = 90
from A
join B m on (A.id=m.id)
where m.key=4 and s.ran=some_input_from_user