SQL select procedure : how to select a range - sql-server

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.

Related

Conditional where clause with IN operator does not work

CREATE TABLE #MyTasks
(TaskId int,
CompanyId int,
YearCol varchar(50),
MonthCol varchar(50),
SomeValue varchar(50)
);
GO
INSERT INTO #MyTasks
SELECT 220,1,2018,1,50553.32
UNION
SELECT 220,2,2018,2,222038.12
DECLARE #Param1 int = 1
DECLARE #Param2 int = 0
SELECT * FROM #MyTasks
WHERE
(#Param1 != 0 AND taskid in (select taskid from #mytasks where companyid = #param1) OR #Param1 = 0)
OR
(#Param2 != 0 AND taskid in (select taskid from #mytasks where companyid = #param2) OR #Param2 = 0) -- because of this condition, all rows are being returned
How to return all rows from #MyTasks table if #Param1 was not passed to stored procedure? I'm initially setting it to 0 and want to use where clause only if was passed and is diffrent from 0.
Just need to use some parentheses on the where clause and add a OR condition.
WHERE
(#Param1 != 0 AND taskid in (select taskid from #mytasks where companyid = #Param1))
or #Param1 = 0 --usually this would be IS NULL
This can be further simplified as
WHERE companyid = #Param1 or #Param1 = 0
Or with multiple parameters...
WHERE
(companyid = #Param1 or #Param1 = 0)
and
(someColumn = #newParam or #newParam = 0)
If you work on same table please doesn’t use not or in use just where clause it’s just too not read full table two times .
It’s can be done by :
CREATE TABLE #MyTasks
(TaskId int,
CompanyId int,
YearCol varchar(50),
MonthCol varchar(50),
SomeValue varchar(50)
);
GO
INSERT INTO #MyTasks
SELECT 220,1,2018,1,50553.32
UNION
SELECT 220,2,2018,2,222038.12
DECLARE #Param1 int = 0
SELECT * FROM #MyTasks
WHERE #param1 = 0 or companyid = #param1

Add columns dynamically and Later Parse values in the respective columns

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)

SSRS page splitting

So I am performing a while loop on 3 stored procs and inserting the data into temp tables and then performing a union on them and when I run the query It returns 10 results but when I make a report out of it in SSRS it returns just the first result and stops! shouldn't it make multiple pages with the other results?
declare #temptable table ( id int )
while (select count(*) from customerid c left join #temptable t on c.id = t.id where t.id is null) > 0 begin
insert into #temptable select min(c.id) from customerid c left join #temptable t on c.id = t.id where t.id is null
declare #id2 varchar(50) = (select max(id) from #temptable)
-- insert into temp tables here
exec DoctorsSDJs #id = #id2
-- insert into temp table
exec LocationSDJs #id = #id2
-- insert into temp tables
exec PatientSDJs #id = #id2
-- performing my union on the 3 tables
end

SQL Trigger after insert update

What is wrong with this code.
If i type like this
Declare tmp as CURSOR FOR
Select i.ID from Inserted
OPEN tmp
Or if i type
Declare tmp as CURSOR FOR
Select i.ID from Deleted
OPEN tmp
Works like a charm but
Is there any way i can write something like this
if #operation <> 3
set #tmp = 'SELECT i.id FROM inserted i '
else
set #tmp =' SELECT i.id FROM deleted i '
DECLARE tmpUpit CURSOR FOR
#tmp
OPEN tmpUpit
Edit :
CREATE TRIGGER [dbo].[ax_Triger] ON [dbo].[extraTable]
FOR INSERT, UPDATE, DELETE AS
SET NOCOUNT ON;
--Capture the Operation (Inserted, Deleted Or Updated)
DECLARE #operation int
DECLARE #Count AS INT
SET #operation = 1
SELECT #Count = COUNT(*)
FROM DELETED
IF #Count > 0
BEGIN
SET #operation = 3
SELECT #Count = COUNT(*)
FROM INSERTED
IF #Count > 0
SET #operation = 2
END
DECLARE tmpUpit CURSOR FOR
SELECT i.id FROM inserted i
OPEN tmpUpit
FETCH NEXT FROM tmpUpit
into #ID WHILE ##fetch_status = 0
begin If Not exists
(SELECT * FROM mytable
where (Operation=3 OR (Operation=1 AND ID=#ID)) AND Status = 0 AND Tablename ='extraTable')
begin INSERT INTO
mytable ([Field1], [Field2],
[ID], [Tablename], [Operation], [Time12], [Status])
VALUES (#Field1, #Field2, #ID, 'extraTable', #operation,GETDATE(),0)
DELETE FROM mytable
WHERE [Field1]=#Field1 And [Field2]=#Field2 And [ID]=#ID And [Tablename]='extraTable'
AND [Operation] = 4 AND [Status] = 0
End
FETCH NEXT FROM tmpUpit into #ID
End CLOSE tmpUpit DEALLOCATE tmpUpit end
i need to insert the value from one table to another depending about the status Inserted/updated/deleted
This is completely untested since the table structures posted did not match the posted trigger code. This should at least demonstrate how you can rethink about this as set based logic instead of row by agonizing row.
CREATE TRIGGER [dbo].[Trigger212] ON [dbo].[Towns]
FOR INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON;
DECLARE #operation int
DECLARE #Variable1 nvarchar(8) = 'Woof'
DECLARE #Variable2 nvarchar(4) = 'Foof'
--Capture the Operation (Inserted, Deleted Or Updated)
IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS (SELECT * FROM deleted)
SET #operation = 1 --Insert
ELSE
IF EXISTS(SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
SET #operation = 2 --update
ELSE
SET #operation = 3 -- DELETE
INSERT Requests
(
Field1
, Field2
, ID
, TableName
, Operation
, TimeU
, Status
)
SELECT 'Woof'
, 'Foof'
, i.ID
, 'Towns'
, #operation
, GETDATE()
, 0
FROM inserted i
LEFT JOIN Requests r on r.ID = i.ID
AND r.Operation = 3
OR (r.Operation = 1 and r.ID = i.ID)
AND r.Status = 0
AND r.TableName = 'Towns'
WHERE r.ID IS NULL
DELETE r
FROM Requests r
JOIN inserted i on i.Field1 = r.Field1
AND i.Field2 = r.Field2
AND i.ID = r.ID
AND i.Operation <> #operation
WHERE r.TableName = 'Towns'
AND r.Status = 0
END
In general I think triggers should be avoided but they have their place. When triggers are appropriate I am generally not a big fan of doing all three operations. Over time it gets really messy because invariably you need to do different logic for the different operations. Splitting them into three triggers makes this eventuality a lot less painful for maintenance.

Use A Bit (bool) Check In A Sql Query

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

Resources