Sql Query with Parameters which might have value or can be null [duplicate] - sql-server

This question already has answers here:
Elegant way to filter a record with nullable field in SQL using nullable parameter
(4 answers)
Closed 4 days ago.
My table as follows:-
declare #table table(Inscode varchar(10), LocId varchar(10), effdate datetime)
insert into #table values('1','102','2023-02-01 00:00:00')
insert into #table values('1',NULL,NULL)
select * from #table
I am passing following parameters:-
declare #InsuranceCode VARCHAR(100)='1'
declare #LocationIds VARCHAR(100)=NULL
declare #EffectiveDate datetime='2023-02-01 00:00:00.000'
I want to built sql statement that is equivalent to
SELECT * from #table where Inscode ='1'
AND LocId IS NULL
AND effdate='2023-02-01 00:00:00.000'
My #LocationIds can have value or can be null, similarly #EffectiveDate can have value or can be null.
I tried following sql query, but I am not getting desired result
SELECT * from #table where Inscode =#InsuranceCode
AND (LocId=#LocationIds OR LocId IS NULL)
AND (effdate=#EffectiveDate OR effdate IS NULL)
Thank you

If you are passing a NULL value and you want to compare NULL to NULL you need to check both values are NULL:
SELECT Inscode,
LocId,
effdate
FROM #table
WHERE Inscode = #InsuranceCode
AND (LocId = #LocationIds OR (#LocationIds IS NULL AND LocId IS NULL))
AND (effdate = #EffectiveDate OR (#EffectiveDate IS NULL AND effdate IS NULL));
If you are on SQL Server 2022 (or an Azure hosted service), you could also use IS NOT DISTINCT FROM:
SELECT Inscode,
LocId,
effdate
FROM #table
WHERE Inscode = #InsuranceCode
AND LocId IS NOT DISTINCT FROM #LocationIds
AND effdate IS NOT DISTINCT FROM #EffectiveDate;

Related

Select all rows if #Parameter = NULL

I have a stored procedure with a parameter, #PolicySymbol, which can accept multiple values. For that I am using a split string function: StringOfStringsToTable
If user selects #ControlNo, then I want to bring data for that controlNo no matter what value is set for #PolicySymbol.
If #PolicySymbol = NULL I want to bring all data for controlNo no matter what policy symbol it related to.
Here is the code sample:
CREATE TABLE #Test (ControlNo int, policy_symbol varchar(50))
INSERT INTO #Test
VALUES (1111, 'CSE'), (2222, 'PRE'), (3333, 'CSE'), (4444, 'GLG'),
(4444, 'PRE'), (4444, 'GLS')
DECLARE
#ControlNo int = 1111,
#PolicySymbol varchar(50) = NULL
SELECT DISTINCT ControlNo, policy_symbol
FROM #Test
WHERE ControlNo = COALESCE(#ControlNo, ControlNo)
-- here, if parameter #PolicySymbol IS NULL I want to include all policy symbols
AND policy_symbol IN (SELECT String FROM [dbo].[StringOfStringsToTable] (#PolicySymbol, ','))
DROP TABLE #Test
A simple, logical OR does the trick.
WHERE ControlNo = COALESCE(#ControlNo, ControlNo)
-- If parameter #PolicySymbol IS NULL I want to include all policy symbols
AND (
#PolicySymbol IS NULL
OR policy_symbol IN (SELECT String FROM [dbo].[StringOfStringsToTable] (#PolicySymbol,','))
)

Get inserted timestamp

in our T-SQL database We have some timestamp column, every time we insert or update a record we select the timestamp from the record the same key we inserted or updated.
We want avoid the double search: for update and for select, we tried something like this:
declare #table table(id int, val timestamp not null)
declare #table2 table(val timestamp)
insert #table(id)
output inserted.val into #table2
values (1)
but it does not compile, i have an error in Italian, something like 'a timestamp column can not be set explicitly'
any hint?
The problem is that TIMESTAMP is a data type that is automatically generated and only exposed as read-only. It's based around an incrementing number within the system.
SQL Server: Cannot insert an explicit value into a timestamp column
Try this:
DECLARE #table TABLE(id INT, val TIMESTAMP NOT NULL)
DECLARE #table2 TABLE(val DATETIME)
INSERT #table (id)
OUTPUT inserted.val INTO #table2(val)
VALUES (1)
SELECT
t.id,
t.val,
CONVERT( TIMESTAMP, t2.val ) AS table2_timestamp
FROM
#table AS t,
#table2 AS t2

How to call a recursive function in sql server

I have a table as follows
cat_id Cat_Name Main_Cat_Id
1 veg null
2 main course 1
3 starter 1
4 Indian 2
5 mexican 2
6 tahi 3
7 chinese 3
8 nonveg null
9 main course 8
10 indian 9
11 starter 8
12 tahi 11
13 chinese 11
(Main_Cat_Id is cat_id of previously added category in which it belongs)
This table is used for the categories the product where veg category has the two sub category main course and starter which is identify by main_cat_id
and those subcategories again has sub category as indian and mexican
And this categorization is dependent on the user; he can add more sub categories to indian, mexican also so that he can have any level of categorization
now I have to select all the subcategories of any node like if I take veg i have to select
(1)veg > (2)main course(1) > (4)indian(2)
> (5)mexican(2)
> (3)starter(1) > (6)thai(3)
> (7)chinese(3)
to form the string as 1,2,4,5,3,6,7
to do this i wrote a sql function as
CREATE FUNCTION [dbo].[GetSubCategory_TEST]
( #MainCategory int, #Category varchar(max))
RETURNS varchar(max)
AS
BEGIN
IF EXISTS (SELECT Cat_Id FROM Category WHERE Main_Cat_Id=#MainCategory)
BEGIN
DECLARE #TEMP TABLE
(
CAT_ID INT
)
INSERT INTO #TEMP(CAT_ID) SELECT Cat_Id FROM Category WHERE Main_Cat_Id=#MainCategory
DECLARE #TEMP_CAT_ID INT
DECLARE CUR_CAT_ID CURSOR FOR SELECT CAT_ID FROM #TEMP
OPEN CUR_CAT_ID
WHILE 1 =1
BEGIN
FETCH NEXT FROM CUR_CAT_ID
INTO #TEMP_CAT_ID;
IF ##FETCH_STATUS <> 0
SET #Category=#Category+','+ CONVERT(VARCHAR(50), #TEMP_CAT_ID)
SET #Category = [dbo].[GetSubCategory](#TEMP_CAT_ID,#Category)
END
CLOSE CUR_CAT_ID
DEALLOCATE CUR_CAT_ID
END
return #Category
END
but this function keep on executing and not gives the desired output i don't understands what wrong is going on plz help me to get this
You dont need a recursive function to build this, you can use a Recursive CTE for that.
Something like
DECLARE #TABLE TABLE(
cat_id INT,
Cat_Name VARCHAR(50),
Main_Cat_Id INT
)
INSERT INTO #TABLE SELECT 1,'veg',null
INSERT INTO #TABLE SELECT 2,'main course',1
INSERT INTO #TABLE SELECT 3,'starter',1
INSERT INTO #TABLE SELECT 4,'Indian',2
INSERT INTO #TABLE SELECT 5,'mexican',2
INSERT INTO #TABLE SELECT 6,'tahi',3
INSERT INTO #TABLE SELECT 7,'chinese',3
INSERT INTO #TABLE SELECT 8,'nonveg',null
INSERT INTO #TABLE SELECT 9,'main course',8
INSERT INTO #TABLE SELECT 10,'indian',9
INSERT INTO #TABLE SELECT 11,'starter',8
INSERT INTO #TABLE SELECT 12,'tahi',11
INSERT INTO #TABLE SELECT 13,'chinese',11
;WITH Recursives AS (
SELECT *,
CAST(cat_id AS VARCHAR(MAX)) + '\' ID_Path
FROM #TABLE
WHERE Main_Cat_Id IS NULL
UNION ALL
SELECT t.*,
r.ID_Path + CAST(t.cat_id AS VARCHAR(MAX)) + '\'
FROM #TABLE t INNER JOIN
Recursives r ON t.Main_Cat_Id = r.cat_id
)
SELECT *
FROM Recursives
I am ashamed, but I used #astander scipt to give string result.
First I created data you gave.
Second I collect rows which I need
And then using XML I put everything in one row (function STUFF removes first comma)
DECLARE #TABLE TABLE(
cat_id INT,
Cat_Name VARCHAR(50),
Main_Cat_Id INT
)
DECLARE #Collected TABLE(
cat_id INT
)
INSERT INTO #TABLE SELECT 1,'veg',null
INSERT INTO #TABLE SELECT 2,'main course',1
INSERT INTO #TABLE SELECT 3,'starter',1
INSERT INTO #TABLE SELECT 4,'Indian',2
INSERT INTO #TABLE SELECT 5,'mexican',2
INSERT INTO #TABLE SELECT 6,'tahi',3
INSERT INTO #TABLE SELECT 7,'chinese',3
INSERT INTO #TABLE SELECT 8,'nonveg',null
INSERT INTO #TABLE SELECT 9,'main course',8
INSERT INTO #TABLE SELECT 10,'indian',9
INSERT INTO #TABLE SELECT 11,'starter',8
INSERT INTO #TABLE SELECT 12,'tahi',11
INSERT INTO #TABLE SELECT 13,'chinese',11
INSERT INTO #TABLE SELECT 14,'chinese',6
DECLARE #nodeID INT = 1;
DECLARE #result VARCHAR(MAX);
;WITH Recursives AS (
SELECT cat_id, main_cat_id
FROM #TABLE
WHERE Cat_Id = #nodeID
UNION ALL
SELECT T.cat_id, T.main_cat_id
FROM #TABLE AS T
INNER JOIN Recursives AS R
ON t.Main_Cat_Id = r.cat_id
)
INSERT INTO #Collected
SELECT cat_id
FROM Recursives
SELECT #result = STUFF(
(SELECT ',' + CAST( cat_id AS VARCHAR)
FROM #Collected
ORDER BY cat_id
FOR XML PATH('')
), 1,1,'')
SELECT #result
Your cursor is looping infinitely because you asked it to keep going until 1 no longer equals 1:
WHILE 1 =1
1=1 is always true so the loop never ends, and you don't explicitly break out of it anywhere.
You would do well to study some examples of cursors, for example this one in the Microsoft T-SQL documentation. They are quite formulaic and the main syntax rarely needs to vary much.
The standard approach after opening the cursor is to do an initial fetch next to get the first result, then open a while loop conditional on ##FETCH_STATUS = 0 (0 meaning successful).
Because you're looking only for unsuccessful cursor fetch states inside your cursor:
IF ##FETCH_STATUS <> 0
The setting of #Category will only happen once the cursor has gone past the last row in the set. I suspect this is exactly what you don't want.
I'm also not sure about the scoping of the #Category variable, since it's an input parameter to the function; I generally create new variables inside a function to work with, but off the top of my head I'm not sure this will actually create a problem or not.
More generally, although I don't totally understand what you're trying to achieve here, a recursive function involving a cursor is probably not the right way to do it, as Adriaan Stander's answer suggests.

How to combine data from different tables using a query

I have a set of tables that look like what I have shown below.
Could you let me know how I can achive the desired output ?
CREATE TABLE #ABC([Year] INT, [Month] INT,Customer Varchar(10), SalesofProductA INT);
CREATE TABLE #DEF([Year] INT, [Month] INT,Customer Varchar(10), SalesofProductB INT);
CREATE TABLE #GHI([Year] INT, [Month] INT,Customer Varchar(10), SalesofProductC INT);
INSERT #ABC VALUES (2013,1,'PPP',1);
INSERT #ABC VALUES (2013,1,'QQQ',2);
INSERT #ABC VALUES (2013,2,'PPP',3);
INSERT #DEF VALUES (2013,1,'QQQ',4);
INSERT #DEF VALUES (2013,1,'RRR',5);
INSERT #DEF VALUES (2013,2,'PPP',6);
INSERT #GHI VALUES (2013,1,'QQQ',7);
INSERT #GHI VALUES (2013,2,'RRR',8);
INSERT #GHI VALUES (2013,3,'PPP',9);
INSERT #GHI VALUES (2013,3,'QQQ',10);
I have a query currently that looks like this . #Month and #Year are supplied as parameters
SELECT
-- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
(SELECT SUM(SalesofProductA) FROM #ABC WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_SalesofProductA]
,(SELECT SUM(SalesofProductB) FROM #DEF WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_SalesofProductB]
,(SELECT SUM(SalesofProductC) FROM #GHI WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_SalesofProductC]
FROM (
-- this selects a list of all possible dates.
SELECT [Year],[Month] FROM #ABC
where Year = #Year and Month = #Month
UNION
SELECT [Year],[Month] FROM #DEF
where Year = #Year and Month = #Month
UNION
SELECT [Year],[Month] FROM #GHI
where Year = #Year and Month = #Month
) AS T;
Right now I see an output like this : for a particular value of #Month and #Year
SalesofProductA, SalesofProductB, SalesofProductC
What I would like to see is :
[Customer],SalesofProductA, SalesofProductB, SalesofProductC
Does anyone know how it can be done ?
SELECT Customer
, SUM(COALESCE(P.[ProductA], 0)) AS [ProductA]
, SUM(COALESCE(P.[ProductB], 0)) AS [ProductB]
, SUM(COALESCE(P.[ProductC], 0)) AS [ProductC]
FROM
(
SELECT Customer , SUM(SalesofProductA) AS Sales, 'ProductA' AS ProductName
FROM #ABC
GROUP BY Customer
UNION ALL
SELECT Customer , SUM(SalesofProductB) AS Sales, 'ProductB' AS ProductName
FROM #DEF
GROUP BY Customer
UNION ALL
SELECT Customer , SUM(SalesofProductC) AS Sales, 'ProductC' AS ProductName
FROM #GHI
GROUP BY Customer
) Q
PIVOT ( SUM(Sales)
FOR ProductName
IN ([ProductA], [ProductB], [ProductC])
)P
GROUP BY Customer
Result
Customer ProductA ProductB ProductC
PPP 4 6 9
QQQ 2 4 17
RRR 0 5 8

IsNumeric Time value problem

Table1
Time
10:00:00
12:00:00
Absent
14:00:00
Holiday
...,
Time column Datatype is varchar
I want to check the time column value is numeric then 'Present'
Tried Query
Select case when isnumeric(time) then 'Present' else time end as time from table1
Showing error in 'then'
How to modify my query according to my requirement
Need Query Help
Try using ISDATE
Returns 1 if the expression is a valid
date, time, or datetime value;
otherwise, 0.
Something like
DECLARE #Table TABLE(
[Time] VARCHAR(50)
)
INSERT INTO #Table SELECT '10:00:00'
INSERT INTO #Table SELECT '12:00:00'
INSERT INTO #Table SELECT 'Absent'
INSERT INTO #Table SELECT '14:00:00'
INSERT INTO #Table SELECT 'Holiday'
SELECT *,
ISDATE(Time),
case when ISDATE(time) != 0 then 'Present' else time end
FROM #Table

Resources