ABout "not in" in SQL Server 2008 - sql-server

I have a problem with SQL query.
This is my code:
set #TimeComing=(Select TimeComing from Bill)
set #TimeCome= DATEPART(hour,#TimeComing)
if(#TimeCome>=22 and #TimeCome<=23)
begin set #Bill=#ByDay set #Day=1 set #Hour=0 end
if(#TimeCome>=21 and #TimeCome<22)
begin set #Bill=#ByHour set #Day=0 set #Hour=1 end
if(#TimeCome>=21 and #TimeCome<=23 and #TimeCome not in (#TimeCome>=21 and #TimeCome<22))
begin set #Bill=#ByDay set #Day=1 set #Hour=0 end
As you see, i want to the 3rd condition - TimeCome not in 21:00 and 22:00 to set Bill=ByDay and Day=1. Because of 2nd Condition is used this Parameter. But i have an error
"Incorrect syntax near '>'."
Please help me this problem, thank you !
Update
This is my idea:
If customer come in 21:00 and go in 22:00 (21:00 to 22:00) => #Bill=#ByHour.
If customer come in 22:00 and go in 23:00 (22:00 to 23:00) => #Bill=#ByDay.
If customer come in 21:00 and go in 23:00 (21:00 to 23:00) => #Bill=#ByDay.

This should be:
if(#TimeCome>=21 and #TimeCome<=23 and not (#TimeCome >= 21 and #TimeCome<22))
But it can be simplified:
if(#TimeCome>=22 and #TimeCome<=23)
But you have already have this as first if statement...

Try this:
set #Bill=#ByDay
if(#TimeCome>=22 and #TimeCome<=23)
begin
select #Day=1, #Hour=0
end
if(#TimeCome>=21 and #TimeCome<22)
begin
select #Day=0, #Hour=1
end
Explanation:
I've moved the set #Bill=#ByDay part outside of the condition since it's the same on every if.
I've removed your third condition entirely, since the first condition is actually the same as what you said you want for the third one.
Now, about the IN operator: it expects a comma delimited list of values, not to be confused with a single variable that contains a comma delimited string!,
so a correct use of it would be and #TimeCome not in (21,22).
Note that something like and #TimeCome not in ('21,22') would not return the results you want.
However, you don't seem to need it at all, as I've already written.

Try this ie, your 3rd condition can be reduced down to this:
if(#TimeCome>=22 and #TimeCome<=23)
EDIT:
I think you dont need the 3rd condition at all. As 1st conditon is equivalent to the 3rd condition.
EDIT:
Try this:
declare #flag = false
if(#TimeCome>=22 and #TimeCome<=23)
begin set #Bill=#ByDay set #Day=1 set #Hour=0 end
if(#TimeCome>=21 and #TimeCome<22)
begin set #Bill=#ByHour set #Day=0 set #Hour=1 set #flag = true end
if(#TimeCome>=21 and #TimeCome<=23 and (#flag = false))
begin set #Bill=#ByDay set #Day=1 set #Hour=0 end

First we cannot use directly where condition as you have done above in the 3rd statement, it will give error for incorrect syntax
You can use not in condition by two ways
1) select sub-query in not in condition, here by updating third statement to
if(#TimeCome>=21 and #TimeCome<=23 and #TimeCome not in
(select #TimeCome where #TimeCome >= 22)) begin set #Bill=#ByDay set #Day=1 set #Hour=0
end
2) by setting values explicitly, here as below
if(#TimeCome>=21 and #TimeCome<=23 and #TimeCome not in (#TimeCome1, #TimeCom2)

Related

Incorrect syntax near Throw - what am I missing?

I am trying to execute a THROW statement like so (value and 12345 being some random values):
use testdb;
go
begin try
if('value' in (select distinct shelf from itemloc))
update itemloc
set shelf = 'value'
where item = '12345';
end try
begin catch
;Throw 160073, 'Failed to update shelf value', 1;
end catch;
Using this reference
I looked at this question and I have the ; before my THROW. I'm also checking the syntax against the reference and fail to see why executing this returns
Msg 102, Level 15, State 1, Line 11
Incorrect syntax near 'Throw'.
You're inside a CATCH, you can't choose your error here, you would just use THROW;. Also, you don't need to start your statement with a semicolon, you already put one at the end of your last statement. It's a terminator (it goes at the end of the line), not at the beginning and end.
If you want to use a custom error, use RAISERROR. For example:
USE TESTDB;
GO
BEGIN TRY
IF('value' IN (SELECT DISTINCT shelf FROM itemloc))
UPDATE itemloc
SET shelf = 'value'
WHERE item = '12345';
END TRY
BEGIN CATCH
DECLARE #ERROR VARCHAR(MAX);
SET #ERROR = 'Failed to update shelf value';
RAISERROR(#ERROR, 11, 160073);
END CATCH

How do i format a sql numeric type with commas on Sybase SQLAnywhere?

I came across the following solution but it does not work on Sybase
SELECT CONVERT(varchar, CAST(987654321 AS money), 1)
I have read the Convert Sybase information but still i receive the same number without the commas.
Have you tried giving a varchar (20) for example instead ? something like :
SELECT CONVERT(varchar(20), CAST(987654321 AS money), 1)
In SqlAnywhere money datatype is a domain, implemented as NUMERIC(19,4).
in CAST function , If you do not indicate a length for character string types, the database server chooses an appropriate length. If neither precision nor scale is specified for a DECIMAL conversion, the database server selects appropriate values.
So maybe this is what's causing the issue, what do you get as output ? do you get 987654321.00 , or just 987654321 ?
Update:
My last suggestion would be using insertstr() function and loop through the char value of your number to insert comma every 3 digits .. this is not the cleanest/easiest way but apparently SQLAnywhere deal with money datatype as normal NUMERIC datatype ...
insertstr() documentation is here.
I would give you a code sample but I don't have SQLAnywhere installed to test it ...
Here is the SP i created based on F Karam suggestion.
CREATE FUNCTION "DBA"."formattednumber"( in #number numeric)
returns char(60)
begin
declare #returnnumber char(60);
declare #workingnumber char(60);
declare #n_ind char(1);
declare #decimalnumber char(10);
declare #tempnumber char(60);
declare #decimalpos integer;
if isnull(#number,'') = '' then
return null
end if;
if #number < 0 then set #n_ind = 'Y'
else set #n_ind = 'N'
end if;
set #workingnumber = convert(char(60),ABS(#number));
set #decimalpos = patindex('%.%',#workingnumber);
if #decimalpos > 0 then
set #decimalnumber = substr(#workingnumber,#decimalpos);
set #decimalnumber = "left"(#decimalnumber,3+1);
set #workingnumber = "left"(#workingnumber,#decimalpos-1)
end if end if;
set #returnnumber = '';
while length(#workingnumber) > 3 loop
set #tempnumber = "right"(#workingnumber,3);
set #returnnumber = insertstr(0,#returnnumber,#tempnumber);
set #workingnumber = "left"(#workingnumber,length(#workingnumber)-3);
if length(#workingnumber) > 0 then
set #returnnumber = insertstr(0,#returnnumber,',')
end if
end loop;
if length(#workingnumber) > 0 then
set #returnnumber = insertstr(0,#returnnumber,#workingnumber)
end if;
if length(#decimalnumber) > 0 then
set #returnnumber = #returnnumber+#decimalnumber
end if;
if #n_ind = 'Y' then set #returnnumber = '-' || #returnnumber
end if;
return(#returnnumber)
end;
You need to distinguish between server-side and client-side formatting. When you use the 'isql' client for example (the TDS client), then the result will be this:
1> select convert(money, 9876543210)
2> go
9876543210
------------------------
9,876,543,210.00
(1 row affected)
But this is purely because the client application happens to format 'money' values this way. Also, this is actually not specific for SQLA, since isql is originally the client tool for ASE (a different Sybase database).
When you run the same conversion at the SQLA server (i.e. as part of an expression in a SQL statement), those commas will not be there since SQLA doesn't have such a built-in formatting style.
If you want this, you should write a SQL function that formats the number as you desire.

PLSQL: IF EXISTS in stored procedure while using loop

I am new to PLSQL. I am trying to create a procedure which iterates through an array.
My requirement is if one of the value is not found in table, it should add into FAILARRAY, otherwise it should add into PASSARRAY.
I was getting no data found exception even if it is handled, it goes out of the loop and next value in the loop is not getting iterated again.
Is there any way we can use if exists command here. Please help.
CREATE OR REPLACE PROCEDURE SCHEMA.PR_VALIDATE
(
FILEARRAY IN STRARRAY,
PASSARRAY OUT STRARRAY,
FAILARRAY OUT STRARRAY,
)
IS
--DECLARE
fileName VARCHAR2 (50);
fileId NUMBER;
BEGIN
for i in 1 .. FILEARRAY.count
loop
fileName := FILEARRAY(i);
DBMS_OUTPUT.put_line (FILEARRAY (i));
SELECT FILEID into fileId FROM TABLE_NAME WHERE FILENAME=fileName;
end loop
END;
I suspect you haven't realised that you can have a PL/SQL BEGIN ... END block, including an exception handler, within a loop. In fact, anywhere you can have PL/SQL statements you can have a block.
You mention an exception handler, although your code doesn't contain one. As you say your code goes 'out of the loop', I can only assume it's, well, outside of the for loop. But you can easily add a block, with an exception handler, inside the for loop, for example:
BEGIN
for i in 1 .. FILEARRAY.count
loop
fileName := FILEARRAY(i);
DBMS_OUTPUT.put_line (FILEARRAY (i));
-- Inner block starts at the line below:
BEGIN
SELECT FILEID into fileId FROM TABLE_NAME WHERE FILENAME=fileName;
-- TODO add to PASSARRAY
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- TODO add to FAILARRAY
END;
end loop
END;
This way, if there are 8 values in FILEARRAY and no data is found in the table for the third value, the NO_DATA_FOUND exception gets caught without exiting the loop and the loop then progresses to the fourth value in FILEARRAY.
You are handling the exception but you need to avoid the exception. Try:
SELECT NVL(FILEID, "<Put Something here or leave it empty") FROM TABLE_NAME WHERE FILENAME=fileName;
That way if it finds a null value in the select it will just pull "" instead. Then you can check to see if your SELECT returns "" and if so populate your FAILARRAY, otherwise populate PASSARRAY.
CREATE OR REPLACE PROCEDURE SCHEMA.PR_VALIDATE(
FILEARRAY IN STRARRAY,
PASSARRAY OUT STRARRAY,
FAILARRAY OUT STRARRAY )
IS
fileName VARCHAR2 (50);
l_n_count NUMBER;
l_n_file_id NUMBER;
BEGIN
FOR i IN 1 .. FILEARRAY.count
LOOP
fileName := FILEARRAY(i);
DBMS_OUTPUT.put_line (FILEARRAY(i));
SELECT COUNT(FILEID) INTO l_n_count FROM TABLE_NAME WHERE FILENAME=fileName;
IF l_n_count =0 THEN
failarray(i):='No Value Found';
elsif l_n_count=1 THEN
SELECT FILEID INTO l_n_file_id FROM TABLE_NAME WHERE FILENAME=fileName;
Passarray(i):=l_n_file_id;
END IF;
END LOOP;
END;
/

SQL Server Function/Proc evaluate an expression(s) return an error if not valid

I would like to take the code below and create a common function to pass in one or more expressions and to return back an error of my choosing.
Example Code:
IF #Variable1 IS NULL AND #Variable IS NULL or #Variable3 is not null
BEGIN
-- EITHER DATASET NAME OR ID MUST BE SUPPLIED.
SET #_msg = 'There was an error'
SET #_returnValue = -1
GOTO ERROR_HANDLER
END
ERROR_HANDLER:
-- CREATE THE CLOSING MESSAGE.
IF #_returnValue <> 0
RAISERROR(#_msg, 18, 2) WITH SETERROR
RETURN #_returnValue
From the above, it would be nice to say something like this below where I could reuse the proc/function and make the code less clutered.
exec ValidateMultipleConditions #Variable1 + 'IS NULL AND ' + #Variable + 'IS NULL or ' + #Variable3 + ' is not null'
Anyway, I think with dynamic SQL being passed in this way I could do something where an complete expression could be sent evaluated, validated and then the code continues or stops with an error.
I wanted to see if the community had better ways of doing this or if I'm on the right path.
Thanks.
I'm not quite sure if I get your question right. But you can easily create an procedure (if it's needed).
CREATE PROCEDURE dbo.errorout #message nvarchar(100), #sev int, #state int
AS
BEGIN
RAISERROR(#message,#sev,#state) WITH NOWAIT
END
But I won't use this at all. I would call RAISERROR() in the place where it occurs, as it will give you more accurate line numbers and procedures in the errorlog.

sql server update + output returning empty value

everybody.. I'm a newbie and I'm trying to make my first "little more complicated query" but does not work fully: here it is:
if NOT EXISTS (Select id,selector from Messages where MID='SYCKY')
Insert into Messages (MID,selector) Values ('SYCKY', 'SaraB|')
ELSE
if exists (
select '1'
from Messages
where charindex ('SaraB|',selector)>0
)
Update Messages
set selector = replace(selector,'SaraB|','') output inserted.selector
where MID='SYCKY'
ELSE
Update Messages
set selector = selector+'SaraB|' output inserted.selector
where MID='SYCKY'
it performs the action required, but in the output I have an empty field only
tried also to add an extra field, like this:
if NOT EXISTS (Select id,selector from Messages where MID='SYCKY')
Insert into Messages (MID,selector) Values ('SYCKY', 'SaraB|')
ELSE
if exists (select '1' from Messages where charindex ('SaraB|',selector)>0)
Update Messages
set selector = replace(selector,'SaraB|',''), T='1' output inserted.T
where MID='SYCKY'
ELSE
Update Messages
set selector = selector+'SaraB|', T='0' output inserted.T
where MID='SYCKY'
but result is the same: T is empty, while I need to to know if "SaraB|" has been added or deleted from the field
What's wrong?
Not quite sure... but maybe this is what you want?
if NOT EXISTS (Select id,selector from Messages where MID='SYCKY')
Insert into Messages (MID,selector) Values ('SYCKY', 'SaraB|')
ELSE
if exists (
select '1'
from Messages
where charindex ('SaraB|',selector)>0
)
BEGIN
Update Messages
set selector = replace(selector,'SaraB|','') output inserted.selector
where MID='SYCKY';
SELECT 'If was true';
END
ELSE
BEGIN
Update Messages
set selector = selector+'SaraB|' output inserted.selector
where MID='SYCKY';
SELECT 'If was false';
END
This will "return" different values depending on how the if evaluates.

Resources