Select all records where function is false - sql

I have a validation function that I'd like to run on each id in a table, and return only those ids which are invalid. Code that I've tried:
select myID
from myDB.dbo.myTable
where (myDB.dbo.validateID(myID) = 0)
Where myDB.dbo.validateID is a scalar-valued function.
This works but returns null for all the valid IDs - I want to only return the invalid ones. What is the most efficient way to return all the invalid rows using this function?
Update:
The validateID function returns 1 if the ID is valid, 0 if it isn't.
My code above returns null if the ID is valid, and the ID if it's not. I want it to instead only return the invalid IDs, without all the null results.

select myID
from myDB.dbo.myTable
where (myDB.dbo.validateID(myID) = 0)
This works but returns null for all the valid IDs
That is simply not possible. If you select myID, you get myID, so if you get null, then myID must be null, and your validateID function is detecting that as invalid.
If your function should treat null as a valid ID, you need to fix your function so that myDB.dbo.validateID(null) returns 1.
If your function should treat null as neither a valid nor an invalid ID, you need to fix your function so that myDB.dbo.validateID(null) returns null.
If your function should treat null as an invalid ID, but you still want to exclude null results, when just add a condition myID is not null to your selection.

I tried the same logic but am getting proper output as expected. Am getting rows returned only when function outputs 0 (ie) Invalid records. I don't see NULL values for valid records.
create table dbo.Contracts1(id int,name varchar(50),pric int)
INSERT INTO dbo.Contracts1
VALUES ( 1,'invalid',40000),
(2,'valid',50000),
(3,'valid',35000),
(4,'invalid',40000)
CREATE FUNCTION Testt(#id INT)
returns INT
AS
BEGIN
DECLARE #ret INT
IF EXISTS (SELECT 1
FROM dbo.Contracts1
WHERE name = 'Valid'
AND id = #id)
SELECT #ret = 1
ELSE
SELECT #ret = 0
RETURN #ret
END
SELECT *
FROM dbo.Contracts1
WHERE dbo.Testt(id) = 0
OUTPUT
id name pric
-- ------- -----
1 invalid 40000
4 invalid 40000

Related

SQL Server WHERE clause : column IS NULL or column = parameter value

The code snippet below is what I'm trying to achieve, but I'm having trouble making it work. If the parameter that gets passed into the procedure is null, I want to only return the rows with a WHERE clause IS NULL, but if there is a value, I want to return the rows that are equal to the value passed in. Dynamic SQL seems like it would work, but I'm curious if there's an easier way I'm missing. Thanks in advance.
PARAM:
#id varchar(10) = '123456789'
SELECT *
FROM TABLE T
WHERE
CASE
WHEN #id IS NULL THEN (id IS NULL)
ELSE id = #id
END
The logic you want is:
WHERE (#id IS NULL AND id IS NULL) OR
id = #id
You're trying to use a CASE expression like a Case (Switch) statement. Switches don't exist in T-SQL, and a CASE expression returns a scalar value not a boolean result.
Don't, however, use CASE expressions in the WHERE, use proper Boolean logic:
SELECT *
FROM YourTable YT
WHERE (ID = #ID
OR (ID IS NULL AND #ID IS NULL))

Return default value as integer from SQL stored procedure

I've a select statement such as which returns the row as int,
I've an if else wherein if no row is found i return -1 as a row.
now, if the row is found, the value is returned in int, where as when no row is found its returned in long.
I've converted the returned value to DataRow in C#
IF EXISTS(SELECT 1 FROM STS st WHERE st.plugin_id = plugin_id)
THEN
SELECT id FROM STS st WHERE st.plugin_id= plugin_id AND st.channel_id = channel_id LIMIT 1;
ELSE
SELECT -1 int(50) AS "id";
end IF;
END
In the IF statement the value for the row "id" is of type int, where is the value of "id" in the else statement is of type long. basically i need to typecast.
2 ways to solve this issue,
1.
Declare value as default with data type.
DECLARE DefaultResponse INT DEFAULT -1;
2.
Cast into UNSIGNED.
SELECT CAST(-1 AS UNSIGNED)

UDF showing weird behavior when checking if variable holds null value

I am trying to write a UDF that is used by a check constraint but seem to keep running into an issue.
When having a complete empty table the following results in 1
declare #a float = (SELECT max(amount) FROM Bid WHERE auctionId = 1)
if(#a is null) select 1
else select 0
But when I try to implement similar logic into an UDF it seems to return 0 every time running it against an empty table.
CREATE FUNCTION dbo.fn_ck_newBidIsHigher(#auction int, #bid numeric(8,2))
RETURNS bit
BEGIN
DECLARE #currentHighestBid float = (SELECT max(amount) FROM Bid WHERE auctionId = #auction)
IF((#bid > #currentHighestBid) OR (#currentHighestBid is null))
BEGIN
RETURN 1
END
RETURN 0
END
GO
've been looking at it for over an hour now (maybe that's the problem), but I can't figure out where it's going wrong.
I am calling the function in the check constraint as follows:
ALTER TABLE Bid ADD CONSTRAINT ck_New_Bid_Must_Be_Higher_Than_Previous_Bid CHECK(dbo.fn_ck_newBidIsHigher(auctionId, amount) = 1)
Instead of using an IF, how about using a CASE? When using a CASE you can have more than 2 possible results. F.e. 1 or 0 or NULL, instead of only 1 or 0.
Also, it's safer to compare values of the same type.
Just to avoid any unexpected side-effects from the implicit cast/convert before the comparison.
CREATE FUNCTION dbo.fn_ck_newBidIsHigher(#auction int, #bid numeric(8,2))
RETURNS bit
BEGIN
DECLARE #currentHighestBid numeric(8,2) = (SELECT max(amount) FROM Bid WHERE auctionId = #auction);
DECLARE #result bit = (
case
when #bid > #currentHighestBid then 1
when #bid <= #currentHighestBid then 0
end);
RETURN #result;
END

SQL Creating a function which checks variables to make a total

I've made 2 views which calculates the profit per reservation.
One calculates the profit from bikes and the other one from accessories.
Now when I tried SUMing them together, I get false reports. I found out why: something a reservation doesnt contain a bike or a accessory. This field gives a NULL return, which makes my SUM function unusable, because it lacks results.
I tried this:
USE Biker
GO
CREATE FUNCTION fnMaxOmzet
(
#Fiets AS int,
#Accessoire AS int
)
RETURNS int
AS
BEGIN
DECLARE #MaxOmzet AS int
IF #Fiets = NULL
SET #MaxOmzet = #Accessoire
ELSE IF #Accessoire = NULL
SET #MaxOmzet = #Fiets
ELSE
SET #MaxOmzet = #Fiets + #Accessoire
RETURN #MaxOmzet
END
But it isn't working because it gives multiple results..
Probably cause I am using '=' while it checking a list.
Does anyone know a way to make this function?
SELECT * FROM dbo.vAccessoireOmzet
SELECT * FROM dbo.vFietsOmzet
https://ibb.co/bTmJ26
Expected result: List of ID 1 - 100 and the total of AccesoireOmzet + FietsOmzet
Personally, I would use an inline Table Function. You'll find the performance is significantly faster.
NExt, you don't test for the value NULL by using the = operator, you use IS NULL.
This should cater for the logic you have above, however it is untested due to missing DDL and sample data:
CREATE FUNCTION dbo.fnMaxOmzet (#Fiets int, #Accessoire int)
RETURNS TABLE AS
RETURN
(
SELECT CASE WHEN #Fiets IS NULL THEN #Accessoire
WHEN #Accessoire IS NULL THEN #Fiets
ELSE #Fiets + #Accessoire
END AS MaxOmzet
)
GO
OK, just seen your comment with this sql: SELECT dbo.fnMaxOmzet((SELECT FietsOmzet FROM dbo.vFietsOmzet), (SELECT AccessoireOmzet FROM dbo.vAccessoireOmzet)).
That syntax is just wrong, sorry. You need to use APPLY and a JOIN. This is pure guess work as we have no DDL and Sample data... however:
SELECT MO.MaxOmzet--, --**Your other columns go here**
FROM vFietsOmzet FO
JOIN vAccessoireOmzet AO ON --**Your JOIN criteria goes here**
CROSS APPLY dbo.fnMaxOmzet (FO.FietsOmzet, AO.AccessoireOmzet) MO;
You need to use IS NULL rather than = NULL.
But you could also use something like this:
USE Biker
GO
CREATE FUNCTION fnMaxOmzet
(
#Fiets AS int,
#Accessoire AS int
)
RETURNS int
AS
BEGIN
RETURN ISNULL(#Fiets, 0) + ISNULL(#Accessoire, 0)
END
You can read here for more information on the behaviour of = NULL.
Update:
I imagine what you might be looking for is something like:
SELECT
ISNULL(F.Huurovereenkomst_id, A.Huurovereenkomst_id) Huurovereenkomst_id
, SUM(dbo.fnMaxOmzet(F.FietsOmzet, A.AccessoireOmzet)) MaxOmzet
FROM
dbo.vFietsOmzet F
FULL JOIN dbo.vAccessoireOmzet A ON F.Huurovereenkomst_id = A.Huurovereenkomst_id
GROUP BY ISNULL(F.Huurovereenkomst_id, A.Huurovereenkomst_id)
use coalesce thats position
USE Biker
GO
CREATE FUNCTION fnMaxOmzet
(
#Fiets AS int,
#Accessoire AS int
)
RETURNS int
AS
BEGIN
RETURN coalesce(#Fiets+#Accessoire,#Fiets,#Accessoire) from MyTableVar;
END

Selecting a user-defined scalar function that takes as a parameter another field

I have a table a with a list of id's, and a user-defined function foo(id) that takes the id and returns a VARCHAR(20).
What I am trying to do is:
SELECT
id,
foo(id) AS 'text field'
FROM a
However, instead of calling the function for each ID number, like I desired, the text comes back the same for every row. I have tested the foo() function manually with the returned ID's and it does not have that problem, so I realize I must not understand something about the evaluation of the query.
This worked for me. I'm not sure what your saying you get.
CREATE TABLE [dbo].[a](
[id] [int] NULL
)
insert into a select 1
insert into a select 2
insert into a select 4
insert into a select 5
CREATE FUNCTION foo(#id int) RETURNS varchar(20)
AS
BEGIN
DECLARE #ResultVar varchar(20)
SELECT #ResultVar = '# - ' + CAST(#id as varchar(20))
RETURN #ResultVar
END
select id, dbo.foo(id) AS 'text field' from a
returns
id text field
----------- --------------------
1 # - 1
2 # - 2
4 # - 4
5 # - 5
6 # - 6
If the output of the function is functionally dependent on the input, then it will be called for each row, as you expect. If you see a different result, it means that you do not pass the correct input or your function output is not dependent on its input.