I Apologize, but I have exposed my question to google_and_ChatGPT. I Think a need a ... human. Is my question so hard ?
To me, yes.
I have two colums in a Table in a SQL Server database.
I have checked that (int)Logicial_Value stays into [0;2] by
Logical_Value BETWEEN 0 AND 2
I need to check if
Int_Value < 5000 WHEN Logical_Value = 0
Int_Value > 9999 WHEN Logical_Value = 2
(Gift : I let you guess what the Logical_Value = 1 should imply)
My Check Constraint Expression is :
CASE
WHEN Logical_Value = 0 THEN Int_Value < 5000
WHEN Logical_Value = 1 THEN Int_Value > 4999 AND Int_Value < 10000
WHEN Logical_Value = 2 THEN Int_Value > 9999
END
The hell, it doesn't work. It just allow any value for Int_Value at each case.
Note that SQL Server Management Studio throws an Error Validating Constraint "foo".
My question is now why it let values (it cannot validate the constraint dear captain) but why it can't validate, and thus, what is the correct syntax ?
I'm feeling I have already RTFM, yes.
You need to rephrase your check constraint with a boolean predicate that doesn't return false for invalid combinations of values. For example:
check (logical_value = 0 and int_value < 5000
or logical_value = 1 and int_value between 5000 and 9999
or logical_value = 2 and int_value > 9999)
Related
I have this code which is part of a stored procedure
INSERT INTO #TempTable
/* A few subqueries, about 100 lines */
WHERE (cartera.ClaSucursal = #pIdSucursal OR #pIdSucursal = -1)
AND (cartera.ClaAsesorActual =
CASE
WHEN #pIdAsesor > 0 THEN #pIdAsesor
WHEN #pIdAsesor = 0 THEN NULL
END
OR #pIdAsesor = -1)
/* Rest of my code, about 200 lines */
SELECT * FROM #TempTable
Basically I have a parameter called #pIdAsesor and depending on its value there can be three possible outcomes.
#pIdAsesor = -1 which brings me all entries regardless of the Id value
#pIdAsesor = sumId which brings me all entries with given Id
#pIdAsesor = 0 which brings me all entries with NULL as the Id
Outcomes 1 and 2 work flawlessly, but scenario 3 doesn't bring back results.
null isn't a value - it's the lack thereof. null is never equal to anything (not even another null), but you can check for it explicitly with the is operator.
You could ditch the case expression and construct this logic with a series of ors:
AND ((#pIdAsesor = -1) OR
(#PIdAsesor = 0 AND cartera.ClaAsesorActual IS NULL) OR
(#pIdAsesor = cartera.ClaAsesorActual))
You can't use = for null in case when result comes null but = null doesn't work. You have to use is null.
I'm trying to use SQL Developer bind variables prompt to speed up query execution, but I'm not getting the desired output: looks like the values I put in get converted in number.
Table description:
Nome Null Type
------------------ -------- ------------
NUM NOT NULL VARCHAR2(13)
IS_OK NUMBER(1)
initial situation:
select NUM, IS_OK from numbers_table where NUM = cast(:dn as varchar2(13));
NUM |IS_OK |
------------|------|
08331930078 |1 |
working updates:
1.
update numbers_table set IS_OK = 0 where NUM = 08331930078;
update numbers_table set IS_OK = 0 where NUM = '08331930078';
ouput:
'1 row updated'
non-working updates:
1.
update numbers_table set IS_OK = 0 where NUM = :dn;
update numbers_table set IS_OK = 0 where NUM = cast(:dn as varchar2(13));
output:
'0 rows updated'
Don't know what else can I do to force the value being parsed as a string.
SQL Developer version 4.1.3.20
That's interesting, and looks like a bug. You don't actually need to cast, the value from the 'enter binds' window is a string anyway, so this works:
update numbers_table set IS_OK = 0 where NUM = :dn;
when the zero-padded string 08331930078 is entered in the dialog.
The cast is not needed but ought to still work. If you run as a script instead, with a defined bind variable, then both forms do work:
var dn varchar2(13);
exec :dn := '08331930078';
update numbers_table set IS_OK = 0 where NUM = :dn;
rollback;
update numbers_table set IS_OK = 0 where NUM = cast(:dn as varchar2(13));
rollback;
You get 1 row updated for both statements. Going back to running as a statement still prompts and still has the same (odd) behaviour even when the bind variable has been defined in a script in the same session.
Incidentally, when you do:
update numbers_table set IS_OK = 0 where NUM = 08331930078;
what you're actually doing, as you can see form the execution plan's predicate section, is:
update numbers_table set IS_OK = 0 where to_number(NUM) = 8331930078;
which will stop any index on the num column being used, and may result in unexpected results - in this case, if these are e.g. UK phone numbers you probably won't have the same value with and without the leading zero, but it's something to be wary of generally.
One way to set a value constraint is to use a database check constraint:
balance integer CHECK (balance > 0)
Is it possible to declare the constraint during an update, for example:
UPDATE xx SET balance = balance + 1000 WHERE user_id=$1 CHECK balance > $2
And be able to do this within one query.
You can add a hack assert. For SQL Server this would be:
UPDATE xx
SET balance = balance + 1000
WHERE user_id=$1
AND IIF((balance + 1000) > $2, 0, 0/0) = 0
This causes a division by zero error in case there is a problem. It's a big hack, but it can be useful as an inline assertion.
I have a situation where I'm trying to filter people that have credits or not. Here's an example Dapper query for reference:
var sql = #"
SELECT *
FROM Person
WHERE (Person.Credits > 0) = #hasCredits";
Connection.Query(sql, new { hasCredits });
I was pretty sure Postgres allows you to do this, hence my surprise when on SQL Server this failed with Incorrect syntax near '='.
With the sample data below, I would expect the query to return the Person with the ID of 1 when hasCredits is FALSE and the Person with the ID of 2 when hasCredits is TRUE.
INSERT INTO Person (PersonId, Credits) VALUES (1, 0), (2, 0);
In SQL Server Is there a way to evaluate whether an expression evaluates to true or false?
I've considered the following (horrible looking) options, but was hoping there was a more elegant solution:
"WHERE (Person.Credits " + (hasCredits ? ">" : "=") + " 0)"
"WHERE (#hasCredits = 1 AND Person.Credits > 0) OR (#hasCredits = 0 AND Person.Credits = 0)"
Considering that when Has credits radio button is selected #hasCredits variable will have 1 else when Doesn't have credits is selected #hasCredits variable will have 0 else #hasCredits variable will be null
SELECT *
FROM Person
WHERE (Person.Credits > 0 and #hasCredits=1) or --Has credits
(Person.Credits <1 and #hasCredits=0) or --Doesn't have credits
(#hasCredits IS NULL) --Don't care
You question was quite plain and the answer is super easy!
case when Person.Credit > 0 then 1 else 0 end = #hasCredits
WHERE CONDITION1='ABC'
AND Status =
CASE #Option
WHEN 1 THEN 'True'
WHEN 2 THEN 'False'
WHEN 3 THEN NULL
WHEn 4 THEN **IN ('True', 'False', NULL)**
END
How do I write a query where my first options match directly using = but my last option needs an IN
The above query gives error, but I want something similar to it, which I am not able to find out.
A CASE statement can't return a set of values... but this query should give you the same results:
WHERE CONDITION1='ABC'
AND Status =
CASE
WHEN 1 THEN 'True'
WHEN 2 THEN 'False'
WHEN 3 THEN NULL
WHEN 4 THEN Status
END
Also, note that unless you have ANSI_NULLS OFF, Status will never = NULL... you would need to use IS NULL for this comparison, and you'd need to forgo the CASE statement altogether.
Skip the CASE statement and use OR. And as per ANSI standard don't compare with NULL:
WHERE CONDITION1='ABC'
AND ((#Option = 1 AND Status = 'True') OR
(#Option = 2 AND Status = 'False') OR
(#Option = 3 AND Status IS NULL) OR
(#Option = 4 AND (Status IS NULL OR Status IN ('True', 'False'))))