Convert Varchar To Time Range - sql

I Have 3 varchar Time Range and it should be Converted to start & Finish time value,
here's the value :
SCH
- 9:00-12:00
- 13-15:00
- 15-17:30
so I tried by myself to split into start time and finish and convert to time value
here's my split Function :
CREATE FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
and I get the start & Finish value by do this in my dev query , but when i tried to convert 15-17:30 , I Got an error Conversion, because the start value is only 15 :
declare #valueToParse varchar(20) = '15-17:30'
select #schtimestart = data from dbo.split(#valueToParse,'-') where id=1
select #schtimefinish = data from dbo.split(#valueToParse,'-') where id=2
SELECT CAST(#schtimestart AS time)
SELECT CAST(#schtimefinish AS time)
how to convert only one value as Time value, or is there any simple conversion?

I Already Fix my Split Function, so if the start time have no Minutes value so it's add automatically
here's my code
USE [Dispatch]
GO
/****** Object: UserDefinedFunction [dbo].[Split] Script Date: 25/10/2013 09:39:51 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
declare #tmp as varchar(20)
While (Charindex(#SplitOn,#RowData)>0)
Begin
SET #tmp = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Insert Into #RtnValue (data)
Select Data = case when ISNUMERIC(SUBSTRING(#tmp,1,2)) = 1 AND ISNUMERIC(SUBSTRING(#tmp,4,2)) = 1 then #tmp else (#tmp + ':00') END
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END

Related

Dynamically updating column value in SQL

I am passing one password value for either 2 or 3 or 4 or 'n' number of usernames.
How to pass the user_id dynamically to the update query ?
update user_table
set column_password = 'password value'
where user_id in ( )
First create the function using this code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[SplitIDs]
(
#List varchar(5000)
)
RETURNS
#ParsedList table
(
ID int
)
AS
BEGIN
DECLARE #ID varchar(10), #Pos int
SET #List = LTRIM(RTRIM(#List))+ ','
SET #Pos = CHARINDEX(',', #List, 1)
IF REPLACE(#List, ',', '') <> ''
BEGIN
WHILE #Pos > 0
BEGIN
SET #ID = LTRIM(RTRIM(LEFT(#List, #Pos - 1)))
IF #ID <> ''
BEGIN
INSERT INTO #ParsedList (ID)
VALUES (CAST(#ID AS int)) --Use Appropriate conversion
END
SET #List = RIGHT(#List, LEN(#List) - #Pos)
SET #Pos = CHARINDEX(',', #List, 1)
END
END
RETURN
END
GO
then in your stored procedure declate #UserIDs varchar(max). You will pass comma separated ID list into this param.
Then in your Stored proc you can have:
update U
set U.column_password = 'password value'
FROM dbo.SplitIDs(#UserIDs) I
INNER JOIN user_table U ON I.ID=U.user_id
CREATE A Function
CREATE FUNCTION [dbo].[FnSplit]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table (Id int identity(1,1), Value nvarchar(100))
AS
BEGIN
While(Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
Store Procedure
CREATE Procedure usp_Multipleparameter (#Users VARCHAR(1000)= NULL)
AS
BEGIN
update user_table
set column_password = 'password value'
where user_id collate database_default IN (SELECT Value FROM dbo.FnSplit(#Users,','))
END
GO
Calling Store Procedure
EXEC usp_Multipleparameter 'User1,User2'
Just a thought. If this is already in a stored procedure it is likely you already have the user_id available to you through a select statement. I would do something like this.
update user_table
set column_password = 'password value'
where user_id in ( select user_id from table
where criteria = '' )

Speed issues with While loops in SQL stored procedures

I'm taking over some code that is trying to store a list of IDs at one time and I find this code to be running quite slow for the actions we are trying to complete. Plus, in certain occasions resulting in deadlocks due to high amounts ids.
USE [store]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UpdateImagePriority]
#separator CHAR(1),
#filename varchar(50),
#parentId int,
#slaveIds varchar(8000)
AS
BEGIN
SET NOCOUNT ON
DECLARE #SLAPriorityint
DECLARE #separator_position INT
DECLARE #array_value VARCHAR(50)
SET #slaveIds = #slaveIds + #separator
SET #SLAPriority= 0
WHILE PATINDEX('%' + #separator + '%', #slaveIds ) <> 0
BEGIN
SET #SLAPriority= #SLAPriority+ 1
SELECT #separator_position = PATINDEX('%' + #separator + '%',#slaveIds )
SELECT #array_value = LEFT(#slaveIds , #separator_position - 1)
SELECT Array_Value = #array_value
SELECT #slaveIds = STUFF(#slaveIds , 1, #separator_position, '')
UPDATE image_info
SET SLA_PRIORITY = #SLAPriority
WHERE FILE=#filename and EXT_PAR_ID=#parentId and SLA_ID=#array_value
END
SET NOCOUNT OFF
END
This is a sample of what we would pass in:
e.g.
separator = ','
filename = 'burgerking'
parentId = '1859'
slaveIds = '15,16,19,20,21,25,28,29,30,38,99'
Any suggestions on how to improve the speed of this code.
Thanks in advance!
What you are looking for is a table-valued function to split your values into a table. Then all you need is a single UPDATE .. FROM .. JOIN statement.
CREATE PROCEDURE [dbo].[UpdateImagePriority]
#separator CHAR(1),
#filename varchar(50),
#parentId int,
#slaveIds varchar(8000)
AS
set #slaveIds = #slaveIds + #separator
;WITH SplitString AS
(
SELECT
1 ID,LEFT(#slaveIds,CHARINDEX(',',#slaveIds)-1) AS Part,RIGHT(#slaveIds,LEN(#slaveIds)-CHARINDEX(',',#slaveIds)) AS Remainder
UNION ALL
SELECT
ID+1,LEFT(Remainder,CHARINDEX(',',Remainder)-1),RIGHT(Remainder,LEN(Remainder)-CHARINDEX(',',Remainder))
FROM SplitString
WHERE Remainder IS NOT NULL AND CHARINDEX(',',Remainder)>0
)
update i
SET SLA_PRIORITY = s.ID
from splitstring s
join image_info i on i.[FILE]=#filename and i.EXT_PAR_ID=#parentId and i.SLA_ID= s.Part
where s.Part > ''
For SQL Server 2000, or just to make the string splitting re-usable, I lifted this function from another question.
create function dbo.SplitString
(
#str varchar(8000),
#separator char(1)
)
returns table
AS
return (
with tokens(p, a, b) AS (
select
1,
1,
charindex(#separator, #str)
union all
select
p + 1,
b + 1,
charindex(#separator, #str, b + 1)
from tokens
where b > 0
)
select
p Id,
substring(
#str,
a,
case when b > 0 then b-a ELSE 8000 end)
AS Part
from tokens
)
GO
Then your SP becomes
CREATE PROCEDURE [dbo].[UpdateImagePriority]
#separator CHAR(1),
#filename varchar(50),
#parentId int,
#slaveIds varchar(8000)
AS
update i
SET SLA_PRIORITY = s.ID
from dbo.splitstring(#slaveIds,#separator) s
join image_info i on i.[FILE]=#filename and i.EXT_PAR_ID=#parentId and i.SLA_ID= s.Part
where s.Part > ''
GO
Use a function to convert the array into an XML document, which is then easy to return as a single column table of integers:
use tempdb
go
create function dbo.ParseIDs(#ids varchar(max), #separator char(1)) returns #rtn table (
id int
)
as
begin
declare #xml xml
set #xml = '<root><n>' + replace(#ids, #separator, '</n><n>') + '</n></root>'
insert into #rtn
select id.value('.', 'int')as id
from #xml.nodes('/root/n') as records(id)
return
end
go
declare #buf varchar(max) = '15,16,19,20,21,25,28,29,30,38,99'
select * from dbo.ParseIDs(#buf, ',')
go
drop function dbo.ParseIDs
go
This returns the following:
id
----
15
16
19
20
21
25
28
29
30
38
99
It would be easy to then to do something like this:
UPDATE image_info
SET SLA_PRIORITY = #SLAPriority
WHERE FILE=#filename and EXT_PAR_ID=#parentId and SLA_ID in (
select id from dbo.ParseIDs(#array_value, ',')
)
This might even be better:
UPDATE tbl
SET tbl.SLA_PRIORITY = #SLAPriority
FROM dbo.ParseIDs(#array_value, ',') as x
inner join image_info tbl on x.id = tbl.SLA_ID
WHERE tbl.FILE=#filename and tbl.EXT_PAR_ID=#parentId
Do a set based update:
USE [store]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UpdateImagePriority]
#separator CHAR(1),
#filename varchar(50),
#parentId int,
#slaveIds varchar(8000)
AS
BEGIN
SET NOCOUNT ON
DECLARE #SLAPriorityint
DECLARE #separator_position INT
DECLARE #array_value VARCHAR(50)
SET #slaveIds = #slaveIds + #separator
SET #SLAPriority= 0
DECLARE #slaveIdTable Table
(
ids INT,
SlaPriority INT
)
WHILE PATINDEX('%' + #separator + '%', #slaveIds ) <> 0
BEGIN
SET #SLAPriority= #SLAPriority+ 1
SELECT #separator_position = PATINDEX('%' + #separator + '%',#slaveIds )
SELECT #array_value = LEFT(#slaveIds , #separator_position - 1)
-- get table of ids
INSERT INTO #slaveIdTable (ids,SlaPriority) VALUES(#array_value,#SLAPriority);
SELECT #slaveIds = STUFF(#slaveIds , 1, #separator_position, '')
END
UPDATE ii
SLA_PRIORITY = #SLAPriority
FROM image_info ii
JOIN #slaveIdTable st ON st.ids = st.SLA_ID
WHERE
st.[FILE] = #filename AND
st.EXT_PAR_ID = #parentId
SET NOCOUNT OFF
END
Richard's answer is a bit more elegant. Didn't see it while I was working on mine.

Separate a TEXT block by new lines

In T-SQL, I need to separate a TEXT value by new lines character and then loop on each line.
In other words, I need an explode() function, but for T-SQL, and I need to to loop on each line.
I tough about creating a new temporary table and storing lines of the string in this table as rows, and then loop on this with a cursor. I'm just not sure about how to separate a string.
Is there a quick way to do this in T-SQL ?
(I supposed your data would be larger than 4000 caracters.)
The split function:
CREATE FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(2000)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
And the explode function:
CREATE FUNCTION dbo.*tableName*_Explode
(
#id int
)
RETURNS #RtnValue table
(
Id int,
Data NVARCHAR(2000)
)
AS
BEGIN
DECLARE #LINEBREAK AS varchar(2)
SET #LINEBREAK = CHAR(13) + CHAR(10)
DECLARE #short_text NVARCHAR(2000)
DECLARE #short_text_length INT
DECLARE #sub_length INT
SET #sub_length = 2000
DECLARE #sub_index INT
SET #sub_index = 1
BEGIN
SET #short_text = (select SUBSTRING(*tableData*,#sub_index,#sub_length) from *tableName* WHERE id = #id)
SET #short_text_length = DATALENGTH(#short_text)
WHILE (#short_text_length > 0)
BEGIN
Insert Into #RtnValue (id,data)
SELECT #id, #short_text
SET #sub_index = (#sub_index + #sub_length)
SET #short_text = (select SUBSTRING(*tableData*,#sub_index,#sub_length) from *tableName* WHERE id = #id)
SET #short_text_length = DATALENGTH(#short_text)
END
IF (SELECT COUNT(*) FROM #RtnValue) = 0
Insert Into #RtnValue (id,data)
SELECT #id, ''
END
RETURN
END

stored proc - executing a query with NOT IN where clause

i have a stored procedure
Create PROCEDURE abc
#sRemovePreviouslySelectedWhereClause nvarchar(max)
AS
BEGIN
SELECT *
FROM table
WHERE nId NOT IN (#sRemovePreviouslySelectedWhereClause)
END;
The parameter #sRemovePreviouslySelectedWhereClause can have values like 0,1 . But this fails with error message:
Conversion failed when converting the nvarchar value ' 0,1 ' to data type int.
Is there any other way to achieve this other than dynamic queries?
First, create a split function which splits your delimited string into a table:
CREATE FUNCTION [dbo].[Split]
(
#String varchar(max)
,#Delimiter char
)
RETURNS #Results table
(
Ordinal int
,StringValue varchar(max)
)
as
begin
set #String = isnull(#String,'')
set #Delimiter = isnull(#Delimiter,'')
declare
#TempString varchar(max) = #String
,#Ordinal int = 0
,#CharIndex int = 0
set #CharIndex = charindex(#Delimiter, #TempString)
while #CharIndex != 0 begin
set #Ordinal += 1
insert #Results values
(
#Ordinal
,substring(#TempString, 0, #CharIndex)
)
set #TempString = substring(#TempString, #CharIndex + 1, len(#TempString) - #CharIndex)
set #CharIndex = charindex(#Delimiter, #TempString)
end
if #TempString != '' begin
set #Ordinal += 1
insert #Results values
(
#Ordinal
,#TempString
)
end
return
end
Then change your where clause as follows:
select
t.*
from [yourTable] t
where t.[ID] not in (select cast([StringValue] as int) from dbo.Split(#sRemovePreviouslySelectedWhereClause,','))
Create FUNCTION [dbo].[fn_Split] (
#List nvarchar(2000), #SplitOn nvarchar(5)
)
RETURNS #RtnValue table (
Value nvarchar(100) )
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
**********
Create PROCEDURE abc
#sRemovePreviouslySelectedWhereClause nvarchar(max)
AS
BEGIN
SELECT *
FROM Table
WHERE nId NOT IN (select * from dbo.fn_Split(#sRemovePreviouslySelectedWhereClause,','))
END;
You have to split the #sRemovePreviouslySelectedWhereClause parameter by ',' and place the resulting values in a temp table. Then your select would look like
select * from table where nId not in (select nId from #tempIds)
This approach you're trying doesn't work. But if you're on SQL Server 2008, you could make use of the new features called Table Valued Parameters.
Basically, you create a user-defined table type
CREATE TYPE dbo.nIdTable AS TABLE(nID INT)
and you can then pass in multiple values in that TVP from the outside (e.g. from ADO.NET or such):
CREATE PROCEDURE abc(#idValues dbo.nIdTable READONLY)
and use that table variable inside your stored proc:
SELECT *
FROM table
WHERE nId NOT IN (SELECT nID FROM #idValues)
You will need to use Dynamic sql for such kind of queries.
first construct the query and
SET #sql = 'select * from table
where nId not in (' + #sRemovePreviouslySelectedWhereClause+ ')'
then use EXEC(#sql) to run the query.

break and return #temp_catid if(true)

i have a following sql function which takes a string word as input it then checks whether the word is equal to a categoryName or not i want it to behave like when the if statement is true it breaks from the loop and return #temp_catid else it returns 0 or 1 how can i do that im new to sql scripting plz help... below is my function
USE [myDB]
GO
/****** Object: UserDefinedFunction [dbo].[udfisEqualToCategory] Script Date: 01/31/2011 10:57:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create FUNCTION [dbo].[udfisEqualToCategory](#word nvarchar(max))
RETURNS INT
AS
BEGIN
--declare a temp category table for data processing
declare #temptbl_category Table
(
indexx int identity(1,1),
categoryid int,
categoryname nvarchar(max)
)
--insert data from feedcrawler.category into temp category table
insert into #temptbl_category
select CategoryId,Name
from Category
--declare some variables to hold the data of current row of temp category table being processed while looping
declare #temp_catid int
declare #temp_catname nvarchar(max)
declare #rowcount int
set #rowcount=(select count(indexx)from #temptbl_category)
declare #I int
set #I=1
--print'given string-> '+ #FullName
--print'string length-> '+convert(nvarchar(max),#strlen)
while(#I <= #rowcount)
begin
select #temp_catname=categoryname,#temp_catid=categoryid from #temptbl_category where indexx=#I
set #temp_catname=lower(#temp_catname)
if(#word=#temp_catname)
begin
return #temp_catid
break
end--end if
set #I=#I+1
END--while loop ends
return 0
end-- function ends
GO
No need to loop, just search the table with WHERE
Create FUNCTION [dbo].[udfisEqualToCategory](#word nvarchar(max))
RETURNS INT
AS
BEGIN
declare #temp_catid int
select
#temp_catid = categoryid
from
Category
WHERE
LOWER(#word) = LOWER(categoryname);
--no match = #temp_catid IS NULL. So change to zero
RETURN ISNULL(#temp_catid, 0);
END
GO