SQL Server database question.
Table schema:
CREATE TABLE [dbo].[TestTable]
(
[ID] [INT] NOT NULL,
[PhaseID] [INT] NULL
) ON [PRIMARY]
Data:
INSERT INTO TestTable
VALUES (1, NULL), (2, 1), (3, 2), (4, NULL)
I am running a SQL query which is supposed to retrieve the record which matches the PhaseId column exactly (it could be null or an integer).. but seem to be missing something.
DECLARE #ID INT, #PhaseID INT
SET #ID = 1
SET #PhaseID = 1
SELECT *
FROM TestTable
WHERE PhaseID = #PhaseID OR #PhaseID IS NULL
If #PhaseID parameter is integer this works fine.
DECLARE #PhaseID INT
SET #PhaseID = 1 --works
But if #PhaseID is null, it returns all the records whereas I need the query to return only the first record & 4th record.
DECLARE #PhaseID INT
SET #PhaseID = NULL
SELECT *
FROM TestTable
WHERE PhaseID = #PhaseID OR #PhaseID IS NULL -- does not work returns all 4 records
How can this be achieved please?
I have referred a few other questions already but have not been successful.
SQL Query Where Clause for Null OR Match (only return 1)?
You need PhaseID instead of #PhaseID :
Select *
from TestTable
Where (PhaseID = #PhaseID OR PhaseID IS NULL);
However, i would over thinking with :
. . .
WHERE (#PhaseID IS NOT NULL AND PhaseID = #PhaseID) OR
(#PhaseID IS NULL AND PhaseID IS NULL);
You can do this with Dynamic SQL.
DECLARE #PhaseID INT
SET #PhaseID = 1
DECLARE #Sql NVARCHAR(MAX)
SET #Sql = 'SELECT * FROM TestTable WHERE '
IF #PhaseID IS NOT NULL
SET #Sql = #Sql + 'PhaseID = #_PhaseID'
ELSE
SET #Sql = #Sql + 'PhaseID IS NULL'
EXEC sp_executesql #Sql,N'#_PhaseID int',#_PhaseID = #PhaseID
Currently you are doing #PhaseID is NULL which brings back 4 rows because you are referencing the parameter for the IS NULL check.
Declare #PhaseID int
SET #PhaseID = NULL
Select *
from #Data
Where PhaseID = #PhaseID OR #PhaseID IS NULL
This brought back row 1 & 4 by using PhaseID as the column reference rather than referencing the parameter.
Select *
from #Data
Where PhaseID = #PhaseID OR PhaseID IS NULL
I have an SP which accepts the Inputtable as parameter, My Inputtable is as shown in the code
`create table inputTable ( id int,ItemQty varchar(100))
insert into inputTable(id, ItemQty) values(1,'a,b,c')
insert into inputTable(id, ItemQty) values(2,'x,y')
insert into inputTable(id, ItemQty) values(3,'l,m,n,o,p')
insert into inputTable(id, ItemQty) values(4,'a,b')
insert into inputTable(id, ItemQty) values(5,'m')`
and SP i have written is like below
`ALTER PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
-----
declare #maxcount as int
set #maxcount='select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename
exec('select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename)
print #maxcount
exec #maxcount
print #maxcount
declare #var varchar(100)
IF EXISTS(SELECT * FROM sys.columns WHERE object_id = Object_id(#tablename))
set #var='alter table '+ #tablename +' ADD column QTY1'
exec(#var)
select * from #tablename
select max(len(ItemQty))-max(len(replace(ItemQty, ',', ''))-1) from inputtable
END`
My table is :
step 1 ) I want to add the columns dynamically to inputtable like QTY1,QTY2,QTY3,QTY4,QTY5 because maximum count of ItemQty column is 5, by considering comma as delimiter as shown in figure1
**step 2) ** Parse values in the respective columns(by considering the delimiter comma (,).as shown in figure2
Later SP: I got till here, But Not getting the second step, that is update Parse values in the respective columns.
ALTER PROCEDURE dynamic_tbl (#tablename varchar(50))
AS
BEGIN
DECLARE #ColumnCount int
DECLARE #rowcount TABLE (Value int);
INSERT INTO #rowcount
EXEC('select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename);
SELECT #ColumnCount = Value FROM #rowcount;
Declare #ColumnName nvarchar(10)='qty_'
Declare #count int =0
IF(#ColumnCount>0)
BEGIN
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'dyn_tbl'))
BEGIN
DROP TABLE dyn_tbl
END
select * into dyn_tbl from inputtable
SET #count=#count +1;
WHile(#ColumnCount>=#count)
BEGIN
SET #ColumnName='qty_'+CONVERT(varchar(2),#count)
EXEC ('ALTER TABLE dyn_tbl ADD ['+#ColumnName +'] varchar(20)')
declare #myvar as varchar(max)
set #myvar='update '+#tablename+' set '+#ColumnName +' =itemQty'
--exec dynamic_tbl 'dyn_tbl'
--select * from dyn_tbl
--CAST('<A>'+REPLACE(ITEMQTY, ',', '</A><A>')+'</A>' AS XML)
print #myvar
exec(#myvar)
SET #count=#count +1;
END
END
----
END
Procedure to alter given table dynamically based on column length as you have asked
Alter PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
drop table ##temp
declare #query1 varchar(max)
exec ( '
create table ##temp (id int identity,columnsl varchar(100))
declare #maxcount as int
set #maxcount = (select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename+')
declare #count int = 1
while (#count <= #maxcount)
begin
declare #colvar nvarchar(100)= ''QTY''
set #colvar = concat(#colvar,#count)
set #count = #count + 1
insert into ##temp select #colvar
end
')
declare #tempstart int = 1
declare #templast int = (select count(*) from ##temp)
declare #updatecol varchar(100) = ''
while (#tempstart <= #templast)
Begin
set #updatecol = (select columnsl from ##temp where id = #tempstart)
exec ('alter table '+#tablename+' Add '+#updatecol+' varchar(100) ')
set #tempstart = #tempstart + 1
end
End
output for inputTable:
id ItemQty QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c NULL NULL NULL NULL NULL
2 x,y NULL NULL NULL NULL NULL
3 l,m,n,o,p NULL NULL NULL NULL NULL
4 a,b NULL NULL NULL NULL NULL
5 m NULL NULL NULL NULL NULL
may not be the best way but works.
edit
Altered above procedure to perform both actions, Please use below procedure
Alter PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
-- declare #tablename varchar(100) = 'inputTable'
drop table #temp if object_id('temp..#temp') is not null drop table #temp
declare #query1 varchar(max)
create table #temp (id int identity,columnsl varchar(100))
exec ( '
declare #maxcount as int
set #maxcount = (select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename+')
declare #count int = 1
while (#count <= #maxcount)
begin
declare #colvar nvarchar(100)= ''QTY''
set #colvar = concat(#colvar,#count)
set #count = #count + 1
insert into #temp
select #colvar
end
')
declare #tempstart int = 1
declare #templast int = (select count(*) from #temp)
declare #updatecol varchar(100) = ''
declare #itemqty varchar(100)
while (#tempstart <= #templast)
Begin
set #updatecol = (select columnsl from #temp where id = #tempstart)
exec ('alter table '+#tablename+' Add '+#updatecol+' varchar(100) ')
set #tempstart = #tempstart + 1
end
declare #sysvar table (id int identity,cols varchar(100))
insert into #sysvar select sys.columns.name AS ColumnName FROM sys.columns JOIN sys.tables ON sys.columns.object_id = sys.tables.object_id WHERE sys.tables.name = 'inputTable'
declare #finvar table (id int identity,cols varchar(100))
insert into #finvar select cols from #sysvar where id not in (1,2)
declare #cat int = 1 declare #dog int = (select max(id) from inputTable)
while (#cat <= #dog)
begin
drop table #tab2
if object_id('temp..#tab2') is not null drop table #tab2
create table #tab2 (id int identity,fnvalues varchar(100))
set #itemqty = (select itemqty from inputTable where id = #cat)
insert into #tab2 select item from [dbo].[fnSplit](#itemQty,',')
declare #cn int = 1
declare #max int = (select max(id) from #tab2)
declare #sql nvarchar (1000);
while (#cn <= #max)
begin
declare #upcol varchar(100) = (select fnvalues from #tab2 where id = #cn)
declare #plscol varchar(100) = (select cols from #finvar where id = #cn)
set #sql = N'update '+#tablename+' set ' + #plscol + '= '''+#upcol+''' where id = '''+cast(#cat as varchar(10))+''' ';
select #sql
exec sp_executesql #sql;
set #cn = #cn + 1
end
set #cat = #cat + 1
End
End
output:
id ItemQty QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c a b c NULL NULL
2 x,y x y NULL NULL NULL
3 l,m,n,o,p l m n o p
4 a,b a b NULL NULL NULL
5 m m NULL NULL NULL NULL
did not optimize the query but works fine.
However, if you have maximum Qty's are known which are in comma separated format then you could use xml node method to separate them into columns.QTY1...QTY5
SELECT DISTINCT ID, ITEMQTY,
a.value('/A[1]', 'VARCHAR(MAX)') as QTY1,
a.value('/A[2]', 'VARCHAR(MAX)') as QTY2,
a.value('/A[3]', 'VARCHAR(MAX)') as QTY3,
a.value('/A[4]', 'VARCHAR(MAX)') as QTY4,
a.value('/A[5]', 'VARCHAR(MAX)') as QTY5
FROM
(
SELECT ID, ITEMQTY,
CAST('<A>'+REPLACE(ITEMQTY, ',', '</A><A>')+'</A>' AS XML) AS ITEMQTY1
FROM inputTable
) A
CROSS APPLY ITEMQTY1.nodes('/A') AS split(a);
Result :
ID ITEMQTY QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c a b c NULL NULL
2 x,y x y NULL NULL NULL
3 l,m,n,o,p l m n o p
4 a,b a b NULL NULL NULL
5 m m NULL NULL NULL NULL
Later, you could replace null by using coalesce() or isnull() function with ''
Use This
First Create a function
CREATE FUNCTION [dbo].[fn_split](
#str VARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE #pos INT
SELECT #str = #str + #delimiter
WHILE LEN(#str) > 0
BEGIN
SELECT #pos = CHARINDEX(#delimiter,#str)
IF #pos = 1
INSERT #returnTable (item)
VALUES (NULL)
ELSE
INSERT #returnTable (item)
VALUES (SUBSTRING(#str, 1, #pos-1))
SELECT #str = SUBSTRING(#str, #pos+1, LEN(#str)-#pos)
END
RETURN
END
GO
and use function like this
Declare #test TABLE (
ID VARCHAR(200),
Data VARCHAR(200)
)
insert into #test
(ID, Data)
Values
(1,'a,b,c')
insert into #test
(ID, Data )
values(2,'x,y')
insert into #test
(ID, Data )
values(3,'l,m,n,o,p')
insert into #test
(ID, Data )
values(4,'a,b')
insert into #test
(ID, Data )
values(5,'m')
select ID,data AS ItemQty,
ISNULL((select item from fn_split(Data,',') where idx in (1)),'') as QTY1 ,
ISNULL((select item from fn_split(Data,',') where idx in (2)),'') as QTY2,
ISNULL((select item from fn_split(Data,',') where idx in (3)),'') as QTY3,
ISNULL((select item from fn_split(Data,',') where idx in (4)),'') as QTY5 ,
ISNULL((select item from fn_split(Data,',') where idx in (5)),'') as QTY5
from #test
Output Same as your Image
instead of using
insert into #test
(ID, Data)
Values
(1,'a,b,c')
you can also assgin it like this
insert into #test
(ID, Data)
Values
(Select Column1, Column2 From YourTable)
I am trying to create a stored procedure which searches employees from the table employee.
My query looks like this
ALTER PROCEDURE [dbo].[EmployeeList]
#CurrentPageNo INT = null,
#PageSize INT = 5,
#FirstName VARCHAR(100),
#Email VARCHAR(100),
#DeptId int = null
AS
BEGIN
DECLARE #StartRecordNo INT, #EndRecordNo INT
IF #CurrentPageNo IS NULL
SET #CurrentPageNo = 1
SET #StartRecordNo = ((#CurrentPageNo - 1) * #PageSize)
SET #EndRecordNo = #StartRecordNo + #PageSize
SELECT
ROW_NUMBER() OVER (ORDER BY CreatedByDate desc) As srno,
EmployeeID, FirstName, LastName, Email, DateOfBirth, Joining,
MobileNumber, MonthsOfExperience, TotalExperience, DepartmentName
FROM
Employee
INNER JOIN
Department ON Employee.DeptId = Department.DepartmentID
WHERE
(ISNULL(#FirstName, '') = '' OR Employee.FirstName LIKE '%' + FirstName + '%')
AND
(ISNULL(#Email, '') = '' OR Employee.Email LIKE '%' + #Email + '%')
AND
(#DeptId IS NULL OR Employee.DeptId = #DeptId)
END
The procedure is compiled successfully. but when execute it like
exec EmployeeList 1,10,'shaili','',null
It shows other records too. Can anyone explain this? I want only the record with the given name.
Result I got:
#Siddhant only little mistake by you. i.e you pass FirstName instead of #FirstName. check below code.
ALTER PROCEDURE [dbo].[Test_EmployeeList]
#CurrentPageNo INT = null,
#PageSize INT=5,
#FirstName VARCHAR(100),
#Email VARCHAR(100),
#DeptId int = null
AS
BEGIN
DECLARE #StartRecordNo INT,#EndRecordNo INT
IF #CurrentPageNo IS NULL
SET #CurrentPageNo=1
SET #StartRecordNo=((#CurrentPageNo-1) * #PageSize)
SET #EndRecordNo=#StartRecordNo + #PageSize
SELECT ROW_NUMBER()OVER(ORDER BY Reg_Date desc) As srno,
F_Name, L_Name, Email, Mobile, Reg_Date from tbl_LoginMaster
inner join tbl_Login_Detail
ON tbl_LoginMaster.User_Id = tbl_Login_Detail.User_Id
WHERE (ISNULL(#FirstName,'')='' OR tbl_LoginMaster.F_Name LIKE '%'+#FirstName+'%') AND
(ISNULL(#Email,'')='' OR tbl_LoginMaster.Email LIKE '%'+#Email+'%') AND
(#DeptId is null OR tbl_LoginMaster.User_Id = #DeptId )
END
GO
exec Test_EmployeeList 1,10,'Mohit','',null
I need to check if someone is out sick, and unfortunately the data is stored in 2 separate tables. And if they are here, I need to execute path A if they are not here I need to execute path B. This is what I was thinking but it produces compile error after compile error. Can someone provide guidance?
Create Table #Uno (Id Int Identity, employee varchar(50))
Select empName
From employeeDatabase
WHERE empStatus = 'Active'
Declare #outSick bit, #empName varchar(50), #N int, #MAXID int
Set #N = 1
SELECT #MAXID = Max(ID)
FROM #Uno
WHILE (#N<=MAXID)
BEGIN
--Second Table that stores this data
Select #outSick = callIn
FROM callinDatabase
WHERE empName = #empName
--Returns Yes or True
If #outSick = 1
Set #N = #N + 1
Else
--If not out sick Do this sql statement
Set #N = #N + 1
End
Why can't you do this all in one query, like below?
select
employeeDatabase.empName,
case
when callinDatabase.callin = '1' then 'Out Sick'
else 'Not Out Sick'
end as OutSick
from employeeDatabase left join callinDatabase
on employeeDatabase.empName = callinDatabase.empName
where employeeDatabase.empStatus = 'active'
Create Table #Uno (Id Int Identity, employee varchar(50))
Select empName
From employeeDatabase
WHERE empStatus = 'Active'
Declare #outSick bit, #empName varchar(50), #N int, #MAXID int
Set #N = 1
SELECT #MAXID = Max(ID)
FROM #Uno <----- HERE
WHILE (#N<=#MAXID) <------- HERE
BEGIN
--Second Table that stores this data
Select #outSick = callIn
FROM callinDatabase
WHERE empName = #empName
--Returns Yes or True
If #outSick = 1
Set #N = #N + 1
Else
--If not out sick Do this sql statement
Set #N = #N + 1
End <-------------- Here
I have this procedure:
USE myDataBase
DECLARE
#id INT = NULL
,#name VARCHAR(250)= NULL
,#id2 INT = NULL
,#flag INT =NULL
SELECT *
FROM dbo.table1 INNER JOIN
dbo.table2 ON id = id2
WHERE (#id IS NULL OR #id = id)
AND (#name IS NULL OR #name = name)
AND (#id2 IS NULL OR #id2 = id2)
Depending on what #flag contains, I need #id2 in where clause to be in a centain range.
Meaning
if #flag = 2 --#flag can contain any value from 1 to 12
I need this line:
AND (#id2 IS NULL OR #id2 = id2)
To be:
AND (#id2 IS NULL OR #id2 IN (61,62,63))
Also:
if #flag = 4 --#flag can contain any value from 1 to 12
I need this line:
AND (#id2 IS NULL OR #id2 = id2)
To be:
AND (#id2 IS NULL OR #id2 IN (74,75,76))
And so on..
How can I do that?
I know is a stupid question, but I cannot make it work :(
Thanks
How about:
AND ((#flag = 2 AND #id2 IS NULL OR #id2 IN (61,62,63)) OR
(#id2 IS NULL OR #id2 = id2) )
EDIT:
AND (((#flag >= 1 AND #flag <=12) AND #id2 IS NULL OR #id2 IN (61,62,63)) OR
(#id2 IS NULL OR #id2 = id2) )
Create a temporary table variable, and query using the contents of that variable.
DECLARE #IdList TABLE
(
Id INT,
)
-- Populate temporary table variable with required Id's depending on #flag value
IF #flag = 1
BEGIN
INSERT INTO #IdList VALUES (#id2)
END
IF #flag = 2
BEGIN
INSERT INTO #IdList VALUES (61), (62), (63)
END
IF #flag = 4
BEGIN
INSERT INTO #IdList VALUES (74), (75), (76)
END
-- Code for other flag values within 1-12
-- Perform query to get results
IF (SELECT COUNT(*) FROM #Temp) = 0
BEGIN
-- No values provided for matching
SELECT *
FROM dbo.table1
INNER JOIN dbo.table2 ON id = id2
WHERE (#id IS NULL OR #id = id)
AND (#name IS NULL OR #name = name)
END
ELSE
BEGIN
-- One or more values provided for matching
SELECT *
FROM dbo.table1
INNER JOIN dbo.table2 ON id = id2
AND id2 IN (SELECT Id FROM #IdList)
WHERE (#id IS NULL OR #id = id)
AND (#name IS NULL OR #name = name)
END
It's not clear how you're handling #id2 = NULL so the final IF clause is to separate the two.