Simple ISEMPTY() function in SQL Server throws a non-boolean type error - sql

I'm trying to write a simple ISEMPTY function in Microsoft SQL Server:
DROP FUNCTION IF EXISTS ISEMPTY;
GO
CREATE FUNCTION ISEMPTY
(#charsequence nvarchar(max))
RETURNS BIT
AS
BEGIN
DECLARE #result BIT;
IF (#charsequence IS NULL OR LEN(#charsequence) = 0)
SET #result = 1
ELSE
SET #result = 0;
RETURN #result;
END
GO
When I want to test it with:
SELECT CASE WHEN dbo.ISEMPTY('') THEN 'REACHED!' END;
I get the following error:
[S0001][4145] Line 1: An expression of non-boolean type specified in a context where a condition is expected, near 'THEN'.
What goes wrong here?

A boolean is expected after when in the case expression, but your function returns a bit.
Try this instead:
SELECT CASE WHEN dbo.ISEMPTY('') = 1 THEN 'REACHED!' END;

The function returns a number so you need a comparison with a number to get a boolean value
CREATE FUNCTION ISEMPTY( #charsequence nvarchar(max))
returns BIT AS
begin
DECLARE #result BIT;
IF (#charsequence IS NULL OR LEN(#charsequence) = 0 )
SET #result = 1;
ELSE
SET #result = 0;
RETURN #result;
end
GO
SELECT CASE WHEN dbo.ISEMPTY('') = 1 THEN 'REACHED!' END;
GO
| (No column name) |
| :--------------- |
| REACHED! |
db<>fiddle here

Related

Calling function with table valued parameters in Postgres

I have been facing a problem from since morning and have spent many hours but failed to call below given function.
Function definition:
CREATE OR REPLACE FUNCTION public.proc_mc2cdnpf_insertupdatev3(
tblnotesv3 typupdate_notesv3,
tbldoclinks typupdate_guidparameter,
iuserid integer,
shtmltext character varying,
OUT snoteid character varying,
OUT inoteid integer,
OUT inoteactivityid integer)
RETURNS record
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
#variable_conflict use_variable
declare sNote VARCHAR;
declare sLoggedInUser VARCHAR(20);
declare dtCurrDateTime timestamp;
declare iCurrDate int;
declare iCurrTime INT;
declare iNewNoteID INT;
BEGIN
/*
proc_MC2CDNPF_InsertUpdateV3
2018-04-23 Dennis Sebenick
2018-04-23
- Initial creation of new proc for storing additional HTML text value.
- This proc is going to help bridge the old note system to a new note storage method
2018-04-25
- Added iNoteID / iNoteActivityID for output
2018-06-01
- Update to typUpdate_NotesV3 - removed additional CDN rows for long text
2091-05-08
Rupali Shah
web 1753-added RTRIM(isnull(NOTE_HDQTRS,'')) while creating sNoteID
*/
/******************************
** File: proc_MC2CDNPF_InsertUpdateV3
** Desc: Insert/Update account notes
** Auth: Rupali Shah
** Date: 2019-05-08
**************************
** Change History
**************************
** Date Dev JIRA Description
**2019-05-08 Rupali Shah Web 1753 -added RTRIM(isnull(NOTE_HDQTRS,'')) while creating sNoteID
*******************************/
SELECT dtCurrDateTime = fnGetDate();
SELECT iCurrDate = fnMC2DateToMC2(dtCurrDateTime);
SELECT iCurrTime = fnMC2DateTimeToMC2(dtCurrDateTime);
/*==========================================
Retrieve Update fields from parameter
============================================*/
select
NoteID,
NOTE_NOTES,
NOTE_LOGGEDINUSER,
coalesce(NOTE_ID, 0)
INTO SNoteID,sNote,sLoggedInUser,iNewNoteID
from
tblNotesV3
LIMIT 1;
/************************************************
2018-04-18 DKS
Added in to update new note table
*************************************************/
IF (iNewNoteID > 0)
THEN
BEGIN
IF (LENGTH(sNote) > 0)
THEN
BEGIN
UPDATE
NoteDetails
SET
sNote = sNote,
sNoteHTML = sHTMLText,
iNoteEditedBy = iUserID,
dtNoteEdited = dtCurrDateTime
WHERE
iNoteID = iNewNoteID;
IF (ROWCOUNT = 0)
THEN
BEGIN
INSERT INTO
NoteDetails
(
iNoteType,
sNote,
sNoteHTML,
iNoteEnteredBy,
dtNoteEntered
)
VALUES
( 9, -- iNoteType - int
sNote, -- sNote - VARCHAR(max)
sHTMLText, -- sNoteHTML - VARCHAR(max)
iUserID, -- iNoteEnteredBy - int
dtCurrDateTime
) RETURNING iNewNoteID;
END;
END IF;
END;
END IF;
END;
ELSE
BEGIN
-- Inserting a New Activity
-- 2018-04-18 DKS
-- - Insert to new note table.
IF (LENGTH(sNote) > 0)
THEN
BEGIN
INSERT INTO
NoteDetails
(
iNoteType,
sNote,
sNoteHTML,
iNoteEnteredBy,
dtNoteEntered
)
VALUES
( 9, -- iNoteType - int
sNote, -- sNote - VARCHAR(max)
sHTMLText, -- sNoteHTML - VARCHAR(max)
iUserID, -- iNoteEnteredBy - int
dtCurrDateTime
) RETURNING iNewNoteID;
END;
END IF;
END;
END IF;
/************************************************
End new note table insert / update
*************************************************/
IF EXISTS(SELECT * FROM MC2CDNPF WHERE MC2CDNPF.iNoteID = iNoteID)
THEN
BEGIN
UPDATE
MC2CDNPF
SET
CDNNOTES = '',
CDNFDATE = fnMC2DateToMC2(TblNotesUpdate.NOTE_DDATE),
CDNREASN = TblNotesUpdate.NOTE_REASN,
CDNPRIOR = TblNotesUpdate.NOTE_PRIOR,
CDNTAGGED = TblNotesUpdate.NOTE_TAGGED,
iNoteID = iNewNoteID
FROM
MC2CDNPF
JOIN
tblNotesV3 TblNotesUpdate
ON
MC2CDNPF.iNoteID = TblNotesUpdate.NOTE_ID
WHERE
MC2CDNPF.CDNDSEQN = 1;
END;
ELSE
BEGIN
SELECT
TRIM(coalesce(NOTE_CMPANY,'')) ||
TRIM(coalesce(NOTE_BUSNSS,'')) ||
TRIM(coalesce(NOTE_CUSNBR,'')) ||
TRIM(coalesce(NOTE_ENTITY,'')) ||
TRIM(coalesce(NOTE_HDQTRS,'')) ||
CAST( iCurrDate AS VARCHAR(8)) ||
CAST( iCurrTime AS VARCHAR(10))
INTO sNoteID
FROM
tblNotesV3
LIMIT 1;
INSERT INTO
MC2CDNPF
(
CDNDSEQN,
CDNNOTES,
CDNCMPANY,
CDNCUSNBR,
CDNBUSNSS,
CDNENTITY,
CDNHDQTRS,
CDNRPTCON,
CDNFULNME,
CDNAGNIDN,
CDNDDATE,
CDNDTIME,
CDNREASN,
CDNTUSER,
CDNADATE,
CDNTAGGED,
CDNFDATE,
CDNPRIOR,
CDNDTASRC,
CDNODATE,
CDNOTIME,
iNoteID
)
SELECT
1,
'', -- 6/1/2018 DKS - no longer storing note in MC2CDNPF
coalesce(NOTE_CMPANY,''),
coalesce(NOTE_CUSNBR,''),
coalesce(NOTE_BUSNSS,''),
coalesce(NOTE_ENTITY,''),
coalesce(NOTE_HDQTRS,''),
coalesce(NOTE_RPTCON,''),
NOTE_FULNME,
coalesce(NOTE_AGNIDN,''),
iCurrDate,
iCurrTime,
NOTE_REASN,
NOTE_TUSER,
iCurrDate,
coalesce(NOTE_TAGGED,''),
iCurrDate,
NOTE_PRIOR,
coalesce(NOTE_DTASRC,''),
iCurrDate,
iCurrTime,
iNewNoteID
FROM
tblNotesV3 TblSource;
END;
END IF;
-- There are attachments to link
IF EXISTS(SELECT * FROM tblDocLinks)
THEN
BEGIN
CALL public.proc_Documents_AddLinkMultiple_LinkID (tblDocLinks, 9, 0, sNoteID, iUserID);
END;
END IF;
iNoteID := iNewNoteID;
iNoteActivityID := 0;
END;
$BODY$;
I am trying to call my function in following two ways:
Method1:
SELECT public.proc_MC2CDNPF_InsertUpdateV3
(
(SELECT w::typupdate_notesv3 FROM (TABLE tblnotesv31) w ) ,
(SELECT w1::typupdate_guidparameter FROM (TABLE tbldoclinks1) w1 ) ,
1,
'test text'
)
But it fails with following error:
ERROR: query has no destination for result data
HINT: If you want to
discard the results of a SELECT, use PERFORM instead. CONTEXT:
PL/pgSQL function
proc_mc2cdnpf_insertupdatev3(typupdate_notesv3,typupdate_guidparameter,integer,character
varying) line 41 at SQL statement SQL state: 42601
Method2:
SELECT *
from proc_MC2CDNPF_InsertUpdateV3
(
(SELECT w::typupdate_notesv3 FROM (TABLE tblnotesv31) w ) ,
(SELECT w1::typupdate_guidparameter FROM (TABLE tbldoclinks1) w1 ) ,
1,
'test text'
)
Again it failed saying:
ERROR: query has no destination for result data HINT: If you want to
discard the results of a SELECT, use PERFORM instead. CONTEXT:
PL/pgSQL function
proc_mc2cdnpf_insertupdatev3(typupdate_notesv3,typupdate_guidparameter,integer,character
varying) line 41 at SQL statement SQL state: 42601
Can please someone help me out that what's actually wrong with my function call?
Starting at line 41 (as the error message told you) you got:
SELECT dtCurrDateTime = fnGetDate();
SELECT iCurrDate = fnMC2DateToMC2(dtCurrDateTime);
SELECT iCurrTime = fnMC2DateTimeToMC2(dtCurrDateTime);
I assume you want to set the variables there. But you're doing it wrong. (It looks like you tried to use SQL Server syntax. Is this an attempt to port a function from SQL Server to Postgres? There are also BEGIN ... END blocks for IFs and ELSEs, which are unnecessary (but harmless) in Postgres but needed in SQL Server.)
Either use INTO:
SELECT fnGetDate() INTO dtCurrDateTime;
SELECT fnMC2DateToMC2(dtCurrDateTime) INTO iCurrDate;
SELECT fnMC2DateTimeToMC2(dtCurrDateTime) INTO iCurrTime;
Or, since you're not actually querying a table, simple assignments should work too:
dtCurrDateTime = fnGetDate();
iCurrDate = fnMC2DateToMC2(dtCurrDateTime);
iCurrTime = fnMC2DateTimeToMC2(dtCurrDateTime);
There might be other lines with the same mistake, you should check the whole code.

Create automatic code

I want to create automatic code example:
B001, B002, B003, B004 .....
I have create the function for that:
CREATE FUNCTION AUTO_CODE()
RETURNS CHAR (4)
AS
BEGIN
DECLARE #KODE CHAR(4)
SELECT #KODE = COUNT (KODE_BARANG)FROM BARANG
IF #KODE>0
BEGIN
SELECT #KODE = RIGHT(KODE_BARANG,4) FROM BARANG
SET #KODE = #KODE+1
END
ELSE SET #KODE=1
RETURN 'B' + LEFT('00',3-LEN(#KODE))+(#KODE)
END
The function above only works for B001 through B010, beyond that it was back to B001. It won't work for B011, B012 or B120.
After that I have try to do with if else:
...
DECLARE KODENYA CHAR (5)
IF #KODE >= 0 AND #KODE <=9
BEGIN
SET #KODENYA = 'B' + LEFT('00',4-LEN(#KODE))+(#KODE)
END
ELSE IF #KODE >= 10 AND #KODE <=99
BEGIN
SET #KODENYA = 'B' + LEFT('0',4-LEN(#KODE))+(#KODE)
END
ELSE IF #KODE >= 100 AND #KODE <=999
BEGIN
SET #KODENYA = 'B' + LEFT('',4-LEN(#KODE))+(#KODE)
END
RETURN #KODENYA
The result is still the same and somehow I get #KODE if it was beyond 9 it return to null and SQL SERVER read it as 0.
Is there another way to create this kind of code in SQL SERVER?
There is no need for multiple if/case just simple FORMAT:
CREATE TABLE #tab(KODE INT);
INSERT INTO #tab(KODE) VALUES (1),(2),(10),(99),(101),(100),(999);
SELECT FORMAT(KODE, 'B00#')
FROM #tab;
LiveDemo
You can easily tweak it for longer codes by changing format string 'B000#'
And in your case:
CREATE FUNCTION [dbo].[AUTO_CODE]()
RETURNS CHAR(4)
AS
BEGIN
DECLARE #KODE INT = (SELECT COUNT(KODE_BARANG)FROM BARANG);
RETURN FORMAT(#KODE, 'B00#');
END
Warning:
You function may return duplicates/create gaps when many concurrent calls occur.
SqlFiddleDemo
Depending on your needs you may consider adding calculated column to your BARANG table:
CREATE TABLE BARANG(ID INT IDENTITY(1,1) PRIMARY KEY,
col2 VARCHAR(120) NOT NULL,
...
KODE AS (FORMAT(ID, 'B00#'))
);

Recursive Stored Procedures

I found this code snipped (Source):
CREATE PROCEDURE rec_fib(n INT, OUT out_fib INT)
BEGIN
DECLARE n_1 INT;
DECLARE n_2 INT;
IF (n=0) THEN
SET out_fib=0;
ELSEIF (n=1) then
SET out_fib=1;
ELSE
CALL rec_fib(n-1,n_1);
CALL rec_fib(n-2,n_2);
SET out_fib=(n_1 + n_2);
END IF;
END
This code works with MySQL. In how far do I have to modify it to run on DB2? I cannot seem to find a running minimal example of an recursive stored procedure for DB2.
This works for me: (I haven't done more than make it work, so alternative coding could also work.)
First, add these two lines:
DECLARE n_3 INT;
DECLARE n_4 INT;
Then modify this small section:
ELSE
set n_3 = n - 1;
set n_4 = n - 2;
CALL rec_fib(n_3,n_1);
CALL rec_fib(n_4,n_2);
That's all. Runs on IBM i 6.1 DB2 UDB.
The following code is from SQL tips for DB2, written by Serge Rielau
CREATE OR REPLACE FUNCTION Fib(n INTEGER) RETURNS DECIMAL(31, 0)
BEGIN
DECLARE res DECIMAL(31, 0);
CASE WHEN n = 0 THEN
SET res = 0;
WHEN n = 1 THEN
SET res = 1;
WHEN n > 1 THEN
BEGIN
DECLARE stmt STATEMENT;
PREPARE stmt FROM 'SET ? = Fib(? - 1) + Fib(? - 2)';
EXECUTE stmt INTO res USING n, n;
END;
ELSE
SIGNAL SQLSTATE '78000' SET MESSAGE_TEXT = 'Bad input';
END CASE;
RETURN res;
END;
/
For more information, please check the source page of this code: https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/recursive_sql_pl?lang=en

SQL multiple if statements, same result set, different argument

I am writing a stored proc that calculates a WHOLE bunch of different things, but I have a bit in it, that is repeated about 9 times.
eg:
if #argA = 1 (true)
select Count(samples) from dbo.X where type = #argAType
if #argB = 1 (true)
select Count(samples) from dbo.X where type = #argBType
if #argC = 1
select Count(samples) from dbo.X where type = #argCType
and so on...
how can I write a function (or something similar) that I can pass in a bit (true or false), and other argument, and only return the result set if true???
Is this what you're looking for? This is the best I can deduce based on the question as it's currently posted.
SELECT COUNT(samples)
FROM dbo.X
WHERE
(type=#argAType AND #argA=1)
OR
(type=#argBType AND #argB=1)
OR
(type=#argCType AND #argC=1)
In function form, I think this is right:
CREATE FUNCTION GetCount(#n AS BIGINT) RETURNS BIGINT
AS
BEGIN
DECLARE #count BIGINT
SELECT #count = COUNT(samples)
FROM dbo.X
WHERE
(type=#argAType AND #argA=1)
OR
(type=#argBType AND #argB=1)
OR
(type=#argCType AND #argC=1)
RETURN #count
END

getting error for if/else in a stored procedure

I am relatively very new to SQL queries but I have this stored procedure where I am trying to get value of a declared variable as mentioned below but getting error,
First line is 20 here,
declare #m_ID_v int
set #m_ID_v = ( select ID_C from M_T where MName_C = #MName_parameter)
declare #g bit
if (select G_L_Column from G_L_table Where M_ID_Column = #M_ID_variable)
set #g_v = 1
else
set #g_variable = 0
Exception I get:
Msg 4145, Level 15, State 1, Procedure GetID, Line 20
An expression of non-boolean type specified in a context where a
condition is expected, near 'set'. Msg 156, Level 15, State 1,
Procedure GetID, Line 21 Incorrect syntax near the keyword 'else'.
Now if I remove declare #g... and try to parse it, no error occurs
EDIT
I want my code to check for returned value by my select statement so "if exists" is not really what am looking for, sorry.
try use if exists:
declare #g_v bit
if exists(select G_L_Column from G_L_table Where M_ID_Column = #M_ID_variable)
set #g_v = 1
else
set #g_v = 0
declare #m_ID_v int
set #m_ID_v = ( select ID_C from M_T where MName_C = #MName_parameter)
declare #g bit
if ((select G_L_Column from G_L_table Where M_ID_Column = #M_ID_variable) = value )
set #g_v = 1
else
set #g_variable = 0
You can't say
if (select ...
You have to compare something with something else in a if statement, or use a boolean function such as exists