How to fetch a result of an int column data type from a table and if no record found select 0 as default in microsoft sql azure - sql

How to fetch a result of an int column data type from a table and if no record found select 0 as default in microsoft sql azure
I had tried ISNULL but it does not work.
In case there is a table named student.
Column_Name data_type
roll_nbr int
name varchar(30)
Select ISNULL(roll_nbr,0) FROM student where name = 'Sam;
I am expecting the query to return roll_nbr from the table if exists else return 0 as default if no rows is found.

You can modify your Azure Sql Query as below
Using COALESCE()
SELECT COALESCE((SELECT Roll_nbr FROM student WHERE NAME = 'Sam'), 0);
(http://sqlfiddle.com/#!18/9a6eaf/2)
The subquery will return the RollNumber if satisfies the where condition else it will return blank/null result. Use of COALESCE function on subquery will return first not null value.
Using ISNULL()
SELECT ISNULL((SELECT Roll_nbr FROM student WHERE NAME = 'Sam'), 0)
http://sqlfiddle.com/#!18/9a6eaf/6
Instead of COALESCE() ISNULL() can be used.
ISNULL function accepts only 2 arguments, used to replace null value and it is T-SQL function.
COALEASCE function is ANSI SQL Standard based and it accepts 1-n arguments it returns first not null value.

SELECT TOP 1
CASE
WHEN EXISTS(SELECT 1 FROM Student WHERE name = 'Sam') THEN roll_nbr
ELSE 0
END
FROM Student

Related

Azure Synapse Analytics SQL Database function to get match between two delimited lists

I'm using Azure Synapse Analytics SQL Database. I'm aware I can't use selects in a scalar function (hence the error The SELECT statement is not allowed in user-defined functions). I'm looking for a work-around since this function does not rely on any tables. The goal is a scalar function that takes two delimited lists parameters, a delimiter parameter and returns 1 if the lists have one or more matching items, and returns 0 if no matches are found.
--The SELECT statement is not allowed in user-defined functions
CREATE FUNCTION util.get_lsts_have_mtch
(
#p_lst_1 VARCHAR(8000),
#p_lst_2 VARCHAR(8000),
#p_dlmtr CHAR(1)
)
RETURNS BIT
/***********************************************************************************************************
Description: This function returns 1 if two delimited lists have an item that exists in both lists.
--Example run:
SELECT util.get_lsts_have_mtch('AB|CD|EF|GH|IJ','UV|WX|CD|IJ|YZ','|') -- returns 1, there's a match
SELECT util.get_lsts_have_mtch('AB|CD|EF|GH|IJ','ST|UV|WX|YZ','|') -- returns 0, there's no match
**********************************************************************************************************/
AS
BEGIN
DECLARE #v_result BIT;
-- *** CAN THIS BE ACCOMPLISHED EFFICIENTLY WITHOUT ANY SELECTS? ***
SET #v_result = (SELECT CAST(CASE WHEN EXISTS (SELECT 1
FROM STRING_SPLIT(#p_lst_1, #p_dlmtr) AS tokens_1
INNER JOIN STRING_SPLIT(#p_lst_2, #p_dlmtr) AS tokens_2
ON tokens_1.value = tokens_2.value)
THEN 1
ELSE 0
END) AS BIT);
RETURN #v_result;
END;
I ditched the function and used this CASE statement. I wanted a function to join on that would be reusable. If anyone can find a function to do this, I will make that the accepted answer.
SELECT ...
FROM tbl_1
JOIN tbl_2
ON
-- wanted: util.get_lsts_have_mtch(tbl_1.my_lst, tbl_2.my_lst, '|') = 1
-- but settled for:
CASE WHEN EXISTS
(SELECT [value]
FROM STRING_SPLIT(tbl_1.my_lst, '|')
INTERSECT
SELECT [value]
FROM STRING_SPLIT(tbl_2.my_lst, '|'))
THEN 1
ELSE 0
END = 1

Is there a way to use in or = with a case statement in the where clause in sql?

I have a stored procedure that may or may not get a string list of int ids. When it doesn't get it the value is: ' '. Other wise its something like this: '500,507,908'
I'm trying to use it like this:
select ID as projectTeamId, Employee_ID, Supervisor_ID
from ProjectTeam
where Project_ID = #projectId and IsDeleted = 0 and
ID in (CASE #stringList WHEN '' THEN ID ELSE (SELECT * from TurnListStringIntoTable(#stringList)) END)
to get a result set but it errors out with this code when the string list comes in blank:
An error has occurred while processing Report 'MassReleaseHoursReport':
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I know its an issue where id needs to = id instead of being in id. Any ideas on how I can have the case statement work with #stringList = '' then id = id else id in (SELECT * from TurnListStringIntoTable(#stringList))?
TurnListStringIntoTable returns a table from a string list which in my case is just the project Team ID
I would recommend boolean logic rather than a case expression:
where
Project_ID = #projectId
and IsDeleted = 0
and (
#stringList = ''
or id in (select * from TurnListStringIntoTable(#stringList))
)
Unrelated side note: if you are running SQL Server, as I suspect, and your version is 2016 or higher, you can use built-in function string_split() instead of your customer splitter.
Sure!
All you have to do is use the parameterless flavor of case:
select *
from my_table t
where t.col_1 = case
when #var in (1,2,3) then "foo"
when #var = 4 then "bar"
when #var in (5,6,7) then "baz"
else "bat"
end
One might note that the when expressions are not limited to looking at the same variable in any way. The only requirement is that they have to be a boolean expression. They're evaluated in order top to bottom. The first when clause that evaluates to true wins and it's then value is returned.
If there's no else and evaluation fails to find a match, the result value is null.
Your problem though, is that case expressions
return a single value, and
that value must be of the same type. Can have it returning a string in some cases and a table variable in another.
So... your where clause should look something like this:
where ...
and 'true' = case
when #stringList = '' then 'true'
when ID in ( select *
from TurnListStringIntoTable(#stringList)
) then 'true'
else 'false'
end
You'll probably find, too, that invoking a user-defined function to convert a comma-delimited string into a table variable within the where clause is probably a Bad Idea™ due to the performance impact that that will have.
You'd be better off to move your TurnListStringIntoTable call outside of the select statement, thus:
declare #list = TurnListStringIntoTable(#stringlist)
select ...
from ProjectTeam pt
where . . .
and #stringlist = ''
OR exists ( select * from #list x where x.ID = pt.ID )

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))

PostgreSQL - check if column exists and nest condition statement

Transactions column's names in below code are dynamicaly generated (so it means that sometimes particular name/column doesn't exist). Using this select it finishes successfully only in case when every of those names exists, if not, I got error like this (example):
Error(s), warning(s): 42703: column "TransactionA" does not exist
SELECT
*,
((CASE WHEN "TransactionA" IS NULL THEN 0 ELSE "TransactionA" END) -
(CASE WHEN "TransactionB" IS NULL THEN 0 ELSE "TransactionB" END) +
(CASE WHEN "TransactionC" IS NULL THEN 0 ELSE "TransactionC" END)) AS "Account_balance"
FROM Summary ORDER BY id;
Could you tell me please how can I check first if the column exists and then how can I nest another CASE statement or other condition statement to make it working in a correct way?
You can build any query dynamically with information from the Postgres catalog tables. pg_attribute in your case. Alternatively, use the information schema. See:
Query to return output column names and data types of a query, table or view
How to check if a table exists in a given schema
Basic query to see which of the given columns exist in a given table:
SELECT attname
FROM pg_attribute a
WHERE attrelid = 'public.summary'::regclass -- tbl here
AND NOT attisdropped
AND attnum > 0
AND attname IN ('TransactionA', 'TransactionB', 'TransactionC'); -- columns here
Building on this, you can have Postgres generate your whole query. While being at it, look up whether columns are defined NOT NULL, in which case they don't need COALESCE:
CREATE OR REPLACE FUNCTION f_build_query(_tbl regclass, _columns json)
RETURNS text AS
$func$
DECLARE
_expr text;
BEGIN
SELECT INTO _expr
string_agg (op || CASE WHEN attnotnull
THEN quote_ident(attname)
ELSE format('COALESCE(%I, 0)', attname) END
, '')
FROM (
SELECT j->>'name' AS attname
, CASE WHEN j->>'op' = '-' THEN ' - ' ELSE ' + ' END AS op
FROM json_array_elements(_columns) j
) j
JOIN pg_attribute a USING (attname)
WHERE attrelid = _tbl
AND NOT attisdropped
AND attnum > 0;
IF NOT FOUND THEN
RAISE EXCEPTION 'No column found!'; -- or more info
END IF;
RETURN
'SELECT *,' || _expr || ' AS "Account_balance"
FROM ' || _tbl || '
ORDER BY id;';
END
$func$ LANGUAGE plpgsql;
The table itself is parameterized, too. May or may not be useful for you. The only assumption is that every table has an id column for the ORDER BY. Related:
Table name as a PostgreSQL function parameter
I pass columns names and the associated operator as JSON document for flexibility. Only + or - are expected as operator. Input is safely concatenated to make SQL injection impossible.About json_array_elements():
Query for element of array in JSON column
Example call:
SELECT f_build_query('summary', '[{"name":"TransactionA"}
, {"name":"TransactionB", "op": "-"}
, {"name":"TransactionC"}]');
Returns the according valid query string, like:
SELECT *, + COALESCE("TransactionA", 0) - COALESCE("TransactionB", 0) AS "Account_balance"
FROM summary
ORDER BY id;
"TransactionC" isn't there in this case. If both existing columns happen to be NOT NULL, you get instead:
SELECT *, + "TransactionA" - "TransactionB" AS "Account_balance"
FROM summary
ORDER BY id;
db<>fiddle here
You could execute the generated query in the function immediately and return result rows directly. But that's hard as your return type is a combination of a table rows (unknown until execution time?) plus additional column, and SQL demands to know the return type in advance. For just id and sum (stable return type), it would be easy ...
It's odd that your CaMeL-case column names are double-quoted, but the CaMeL-case table name is not. By mistake? See:
Are PostgreSQL column names case-sensitive?
How to pass column names containing single quotes?
Addressing additional question from comment.
If someone used column names containing single quotes by mistake:
CREATE TABLE madness (
id int PRIMARY KEY
, "'TransactionA'" numeric NOT NULL -- you wouldn't do that ...
, "'TransactionC'" numeric NOT NULL
);
For the above function, the JSON value is passed as quoted string literal. If that string is enclosed in single-quotes, escape contained single-quotes by doubling them up. This is required on top of valid JSON format:
SELECT f_build_query('madness', '[{"name":"''TransactionA''"}
, {"name":"TransactionB", "op": "-"}
, {"name":"TransactionC"}]'); --
("''TransactionA''" finds a match, "TransactionC" does not.)
Or use dollar quoting instead:
SELECT f_build_query('madness', $$[{"name":"'TransactionA'"}
, {"name":"TransactionB", "op": "-"}
, {"name":"TransactionC"}]$$);
db<>fiddle here with added examples
See:
Insert text with single quotes in PostgreSQL
Assuming that id is a unique id in summary, then you can use the following trick:
SELECT s.*,
(COALESCE("TransactionA", 0) -
COALESCE("TransactionB", 0) +
COALESCE("TransactionC", 0)
) AS Account_balance
FROM (SELECT id, . . . -- All columns except the TransactionX columns
FROM (SELECT s.*,
(SELECT TransactionA FROM summary s2 WHERE s2.id = s.id) as TransactionA,
(SELECT TransactionB FROM summary s2 WHERE s2.id = s.id) as TransactionB,
(SELECT TransactionC FROM summary s2 WHERE s2.id = s.id) as TransactionC
FROM Summary s
) s CROSS JOIN
(VALUES (NULL, NULL, NULL)) v(TransactionA, TransactionB, TransactionC)
) s
ORDER BY s.id;
The trick here is that the correlated subqueries do not qualify the TransactionA. If the value is defined for summary, then that will be used. If not, it will come from the values() clause in the outer query.
This is a bit of a hack, but it can be handy under certain circumstances.
Check this example:
UPDATE yourtable1
SET yourcolumn = (
CASE
WHEN setting.value IS NOT NULL
THEN CASE WHEN replace(setting.value,'"','') <> '' THEN replace(setting.value,'"','') ELSE NULL END
ELSE NULL
END
)::TIME FROM (SELECT value FROM yourtable2 WHERE key = 'ABC') AS setting;

Select all records where function is false

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