As you can see i have this condition in my query
if lower('HP||2008|201408')=lower(#serial1) or lower('HP||2008|201408')=lower(#serial2)
select 1
else select 0
But the sql skips my condition and return 0 ,but the condition is true .Why ?
All variables are nvarchar(max) data type .
See, you're comparing 'HP||2008|201408' (one pipe) with serial2 that is equal to 'HP||2008||201408' (two pipes)
(don't know the value of serial1)
The condition is NOT true, that is clear even in the screenshot.
#serial2 does NOT have the same value as what you are checking for - look at it again.
Related
I have the following tasks in SSIS:
In Check Stock task, I execute a stored procedure which returns 0 or 1:
CREATE PROCEDURE [dbo].[SP_CheckStockAvailability]
AS
BEGIN
DECLARE #ItemGID nvarchar(250)=(SELECT TOP (1) ItemGID FROM XMLOrderlines WHERE Comparison='0')
SELECT CASE
WHEN #ItemGID IS NOT NULL
THEN CAST (0 AS bit)
ELSE CAST (1 AS bit)
END AS Comparison
FROM XMLOrderlines
END
GO
I would like to execute Reject Order (on the right) task if the result is 1 and, if not, to execute the one from the left. I set to export the result of the procedure in a variable, Boolean data type with a default value of "False".
If I edit the precedence constraint and I set Expression as evaluation operation and then choose the variable from the previous task, either way it does not go to the next task that is supposed to. What am I missing? I tried what I found on the web but nothing helped me. Thanks!
Solution
You have to set the following values:
Reject Order
Evaluation operation: Expression and Constraint
Value: Success
Expression: #[User::Result] = 1
OR
#[User::Result]
Accept Order
Evaluation operation: Expression and Constraint
Value: Success
Expression: #[User::Result] = 0
OR
!#[User::Result]
Screenshot
Suggestions
I think it is better to add a TRY...CATCH block to your procedure, so if it encounters an error the result will be 1 and the Order is rejected:
CREATE PROCEDURE [dbo].[SP_CheckStockAvailability]
AS
BEGIN
BEGIN TRY
DECLARE #ItemGID nvarchar(250)=(SELECT TOP (1) ItemGID FROM XMLOrderlines WHERE Comparison='0')
SELECT CASE
WHEN #ItemGID IS NOT NULL
THEN CAST (0 AS bit)
ELSE CAST (1 AS bit)
END AS Comparison
FROM XMLOrderlines
END TRY
BEGIN CATCH
SELECT 1 AS Comparison
END CATCH
END
GO
Try choosing Evaluation Operation to Expression and Constraint and the expression has to be smth like #[User::Result] = 1. The expression has to return True or False.
For more informations, follow this link:
Working with Precedence Constraints in SQL Server Integration Services
The expression for 1/True should be #[User::Result], as you have, and the expression for 0/False should be !#[User::Result] (notice the exclamation mark).
You may also want to look into using "Expression and Constraint" as an "Evaluation operation", as without that, the flow will continue regardless of whether "Check stock" succeeds or fails (unless that is the desired behaviour). The "Constraint" part of this is what the "Value" field represents - in your image it is set to Failure, but greyed out (due to having only "Expression" selected) and therefore inactive.
I'm creating a stock market database and am stumped that the following works correctly EXCEPT for the last select that returns results (after which the select does not change on subsequent loops). I've tried to simplify the code as follows, thanks in advance for feedback (I'm still noob):
Three tables:
BuyOrders
SellOrders
MatchedOrders
Stored procedure to process a NewBuyOrder:
Insert NewBuyOrder to BuyOrders;
While (NewBuyOrder.SharesRemaining > 0 )
SELECT TOP 1
FROM SellOrders
WHERE SellOrders.Price <= NewBuyOrder.Price
ORDER BY SellOrders.Price, SellOrders.TimePlaced;
IF NewBuyOrder.SharesRemaining < SellOrders.SharesAvailable
UPDATE SellOrders.SharesAvailable = [difference];
UPDATE BuyOrders = 0;
INSERT INTO MatchedOrders;
SET NewBuyOrder.SharesRemaining = 0;
BREAK;
ELSE
UPDATE SellOrders = 0;
UPDATE BuyOrders = [difference];
INSERT INTO MatchedOrders;
SET NewBuyOrder.SharesRemaining = [difference];
CONTINUE;
In hope it might help someone else, I found the issue . . . I'm using local variables to store the matched SellOrderID. As such if the Select returns no match on a second pass through then the local variables were not getting updated (and hence erroneously reused in subsequent while loops until the If kicked in).
So I put a SET SellOrders.ID = 0 into the WHILE loop before the Select then below the Select added a IF SellOrders.ID = 0 and inside that a SET NewBuyOrder.SharesRemaining = 0 and BREAK (then made the first IF above into an ELSE IF).
I need to revisit the process to see if I can make it more elegant but would sincerely welcome thoughts on better ways to accomplish a process for matching the best available counteroffers in sequence. I've read but don't know much about cursors, plus think it transactionally superior not to SELECT a prioritized table of all matches rather than using my iterative loop -- but also have read suggestions not to use loops in SQL. Comments?
In addition I note the following: By itself a Select with no results returns a null set. Thus my original plan was to Select into my SP local variables and then use an IF EXISTS. I assume the local variable exists upon instantiation (even with no value) but am surprised that after a Select into the local variable with no results also did not fail an IF NULL test (i.e. presumably NULL cannot be inserted into a variable). What then is the value of an instantiated local variable with no value -- Blank?
I don't get the simple boolean algebra on my sql-server. According to msdn, the following statement should return "1", but on my server it returns "0".
Can you help me?
SET ANSI_NULLS ON
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END
Please have a look at msdn. There it clearly states: "Comparing NULL to a non-NULL value always results in FALSE." - no matter what the ANSI_NULLS-setting is. Thus "1=NULL" should be FALSE and NOT(FALSE) should thus be TRUE and the statement should return "1".
But on my machine, it returns "0"!
One explanation might be, that "1=NULL" evaluates to "UNKNOWN". NOT(UNKNOWN) is still UNKNOWN (msdn), which would force the CASE-Statement into the ELSE.
But then the official documentation of the equals-operator would be wrong. I cannot believe this!
Can anybody explain this behaviour?
Thank you very much for any help!
Edit (2012-03-15):
One thing I just found that might be of interest for some of you:
CREATE TABLE #FooTest (Value INT)
ALTER TABLE #FooTest WITH CHECK ADD CONSTRAINT ccFooTestValue CHECK (Value>1)
PRINT '(NULL>1) = ' + CASE WHEN NULL>1 THEN 'True' ELSE 'False' END
INSERT INTO #FooTest (Value) VALUES (NULL)
The print-Statement writes 'False', but the insertion runs without error.
SQL-Server seems to negate the check-constraint in order to search for rows that do not fulfill the constraint-check:
IF EXISTS (SELECT * FROM inserted WHERE NOT(Value>NULL)) <Generate error>
Since the check-constraint evaluates to UNKNOWN, the negation is also UNKNOWN and SqlServer does not find any row violating the check-constraint.
Yes that link is wrong. File a documentation bug on Microsoft Connect.
Sql uses three valued logic not boolean logic. true, false, and unknown
Most comparison operators (i.e. excluding IS [NOT] NULL) involving NULL result in unknown not True or False. Negating unknown yields unknown as per the truth tables shown here.
The MSDN page for Equals that you link to definitely appears incorrect.
Check the MSDN page for SET ANSI_NULLS.
When SET ANSI_NULLS is ON, all comparisons against a null value
evaluate to UNKNOWN.
To get that example SQL statement to work as expected, you should use compare using "IS NULL" or "IS NOT NULL" instead of using the equals operator (=). For example:
SELECT CASE WHEN NOT(1 IS NULL) THEN 1 ELSE 0 END
OR
SELECT CASE WHEN (1 IS NOT NULL) THEN 1 ELSE 0 END
You want to read the documentation on ANSI_NULLS. SQL actually implements a ternary logic, not boolean logic, where a comparison operation can result in true, false or undefined. Basically, this means that the explanation you proffered is correct.
This can be demonstrated with the following query:
SET ANSI_NULLS ON
SELECT CASE
WHEN (1=NULL) THEN 0
WHEN NOT(1=NULL) THEN 1
ELSE -1
END
Which results in -1 on my machine (SQL Server 2005 Enterprise). Changing the first line to SET ANSI_NULLS OFF produces 1 as expected.
So, is the official documentation wrong? I'd submit that is somewhat misleading. It says that it results in FALSE. Obviously this is wrong. What the documentation meant to say is that comparing a non-null to NULL always results in a mismatch whose value also depends on ANSI_NULLS.
Of course, on SQL Server 2012, the ANSI_NULLS setting has been removed, and therefore setting it any which way will not change the result.
It's not boolean logic, its trinary logic: {True, False, I Don't Know.} Break it down this way:
IF 1=NULL
print 'True'
else
print 'False'
Generates False because 1=NULL equals NULL, aka "not True"
IF not(1=NULL)
print 'True'
else
print 'False'
Also generates False because not(1=NULL) equals not(NULL) equals NULL, aka "not True". This gets you to
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END
which as per above is the same as
SELECT CASE WHEN NULL THEN 1 ELSE 0 END
which, since NULL is not true, resovles to the ELSE clause.
In short, as far as I'm concerned the documentation is incorrect. Distressing, but not unique, and so not entirely surprising.
Try using EXISTS in a subquery, it uses 2 valued logic and will give you the true/false you are looking for.
From BOL (credit to Thomas):
SET ANSI_NULLS ON affects a comparison only if one of the operands of
the comparison is either a variable that is NULL or a literal NULL. If
both sides of the comparison are columns or compound expressions, the
setting does not affect the comparison.
So I guess the NOT operation is checking 1=NULL which is unknown and because this is not a variable or literal NULL gets the ELSE part of your comparison as you hypothesised.
1=NULL seems to return FALSE only when ANSI_NULLS is OFF. Otherwise it's indeterminate. The msdn page probably needs to be edited to clarify that point.
SET ANSI_NULLS OFF
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns true
go
SET ANSI_NULLS ON
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
go
I'm having some difficulty in understanding the following WHERE clause in a T-SQL (SQL Server 2000/2005) query:
update #tempTable
SET
Total_Avg=isnull(TerminationReason,'terminated'),
Individual_Subscriptions=null,
Business_Subscriptions=null,
Other_subscriptions=null,
-- snip. 10 more fields set to NULL.
PMIE_BI=null,
Digital_Editions_BI=null
where
(
AbcTerminationDate<=dbo.fnGetPeriodFinalDate(#periodid)
and (AbcTerminationDate!=19000101 or AbcTerminationDate is null)
and (Total_Avg is not NULL or PrevTotalAvg is not NULL)
)
Specifically, the second clause doesn't make sense to me - it's 2 sub-clauses separated by the OR operator seem contradictory.
The AbcTerminationDate field is declared as INT NULL in a table called Members. I believe a date of 19000101 in the system means NULL or a default value or no value, i.e. that a member is NOT terminated. So the query appears to blank out a whole lot of fields/figures if a member is marked as terminated, which would be when the AbcTerminationDate is NULL or has the default value.
Without knowing any more information, what do you make of it?
It does look like those are contradictory. Perhaps they meant
and !(AbcTerminationDate==19000101 or AbcTerminationDate is null)
?
Whatever 19000101 is "supposed" to mean, it is not the same as NULL in the eyes of the database. NULL is NULL. If you try to evaluate any other value to NULL then it can become problematic, because NULL means "unknown". For example, does 1=NULL? Maybe it does, maybe it doesn't. In fact, you can't even say that NULL=NULL, because each NULL is unknown so might or might not be equal to the other. It's safest to explicitly check for NULL conditions.
EDIT:
As I point out in my comment, if NULLs are to be included then the first part of the query precludes that. Here is how it should be written if NULLs should be included:
(
(
(
AbcTerminationDate <= dbo.fnGetPeriodFinalDate(#periodid) AND
AbcTerminationDate != 19000101
) OR
AbcTerminationDate is NULL
) AND
(Total_Avg is not NULL or PrevTotalAvg is not NULL)
)
If the "or" arg were outside the () grouping it would negate:
AbcTerminationDate<=dbo.fnGetPeriodFinalDate(#periodid)
[edit]
Basically it's saying to take whatever results are true from that 1st clause, and perform an additional filter to make sure it's not 19000101 or it's null, are most likely exceptional values for the fnGetPeriodFinalDate function to properly evaluate.
In postgres you can do a comparison against multiple items like so:
SELECT 'test' IN ('not','in','here');
Which is the same as doing:
SELECT ('test' = 'not' OR 'test' = 'in' OR 'test' = 'here');
Is there a functional equivalent for SQL Server ?
It is supported, but you will need to put the expression somewhere that accepts a boolean expression. For example, in a case statement:
select case when 'test' in ('not','in','here') then 1 else 0 end
-----------
0
(1 row(s) affected)
Or a where clause:
select * from T where C in (1,3,5,7,9)
this should give similar results in all recent versions of MSSQL. You could also write a scalar function to shorten things up a bit.
select case
when 'test' IN ('not', 'in', 'here') then 1
else 0
end;
This will give 1 if 'test' is in the comparison set 1 or more times, or 0 if it isn't.
SELECT CAST(COUNT(*) AS BIT) as IsItHere WHERE 'test' IN('not','in','here')
Note that the cast isn't strictly necessary, but may be useful if this is called from another language... It should then resolve to a boolean.
EDIT: According to MSSQL Query planner, this is executed ~4 times faster then the CASE method. YMMV.