Actually I want to insert multiple rows to a table.
The Structure of the table is
Create Table tbl_username
(id int autoincrement,
username varchar(100),
Primary key(id))
and I tried to insert multiple rows like
Declare #s as varchar(100)
set #s='(''name1''),(''name2'')'
insert into tbl_username(username)values #s;
but I get the output as
id username
1 (''name1''),(''name2'')
Actually the required output for me is
id username
1 name1
2 name2
How can I achieve this?
Use dynamic SQL
Declare #s as varchar(100)
Declare #sql as varchar(max)
set #s='(''name1''),(''name2'')'
set #sql = 'insert into tbl_username(username) values ' + #s;
execute(#sql);
However I would avoid dynamic SQL where possible.
The standard way to do it if your values are not in a variable is:
INSERT INTO tbl_username(username) values ('name1'),('name2')
Or
INSERT INTO tbl_username(username) values ('name1')
INSERT INTO tbl_username(username) values ('name2')
If possible, opt for one of the above instead of the dynamic option originally mentioned.
insert into tbl_username(username)values ('name1'),('name2'),.....;
Here because username is of type varchar so it's considering #s as single value and inserting it in one row.
The below logic makes use of substring feature:
DECLARE #s as varchar(100), #Delimiter VARCHAR(1)
SET #s = 'name1,name2'
SET #Delimiter = ','
DECLARE #Position INT, #ListItem VARCHAR(MAX)
WHILE CHARINDEX(#Delimiter, #s) > 0
BEGIN
SELECT #Position = CHARINDEX(#Delimiter, #s)
SELECT #ListItem = SUBSTRING(#s, 1, #Position-1)
INSERT INTO tbl_username
SELECT #ListItem
SELECT #s = SUBSTRING(#s, #Position+1, LEN(#s)-#Position)
END
INSERT INTO tbl_username
Select #s
SELECT * FROM tbl_username
Please try: http://sqlfiddle.com/#!6/d0f76/1/0
Related
Currently I'm using SQL Server Management Studio v18, and I want to iterate a Table Type using a while loop, so I do:
CREATE TYPE [VarcharIdTableType] AS TABLE
(
[FileName] VARCHAR(MAX)
)
Then I use a while loop as:
DECLARE #FileTableType [VarcharIdTableType]
INSERT INTO #FileTableType
VALUES ('test1'),('test2'),('test3')
DECLARE #FileCount INT = (SELECT COUNT(*) FROM #FileTableType), #RowCount INT = 0
WHILE #RowCount <= #FileCount
BEGIN
DECLARE #Content VARCHAR(555)= CONCAT('File name ', #filename)
SET #RowCount = #RowCount + 1;
END
So I want to get each FileName depending of iteration number, how can I achieve that?
IMPORTANT: Do you actually need a loop? As you haven't shown us what your desired final outcome is we are unable to comment. But in many cases a set based approach will accomplish what you need and if so it should be used.
Making a few assumptions, such as no ID column in your table, and being able to delete rows from your table variable, I would do the following using exists rather than counting rows.
DECLARE #FileTableType TABLE ([Name] VARCHAR(MAX));
INSERT INTO #FileTableType([Name]) VALUES ('test1'), ('test2'), ('test3');
DECLARE #Content VARCHAR(MAX) = '', #Filename VARCHAR(MAX);
WHILE EXISTS (SELECT 1 FROM #FileTableType)
BEGIN
SELECT TOP 1 #Filename = [Name] FROM #FileTableType;
SET #Content = CONCAT('File number ', #Filename);
DELETE FROM #FileTableType WHERE [Name] = #Filename;
END;
However having a known unique identifier on the values in the table variable would be better because if you have duplicate filenames the first code will have issues.
DECLARE #FileTableType TABLE (id INT IDENTITY(1,1), [Name] VARCHAR(MAX));
INSERT INTO #FileTableType([Name]) VALUES ('test1'), ('test2'), ('test3');
DECLARE #Content VARCHAR(MAX) = '', #Filename VARCHAR(555), #FileId INT;
WHILE EXISTS (SELECT 1 FROM #FileTableType)
BEGIN
SELECT TOP 1 #FileId = id, #Filename = [Name] FROM #FileTableType;
SET #Content = CONCAT('File number ', #Filename);
DELETE FROM #FileTableType WHERE id = #FileId;
END;
Note the best practices:
Terminating all statements with a semi-colon
Listing all columns when inserting
Using VARCHAR(MAX) for #Content since the filename is.
I want to search for a specific part of a nvarchar text string in a column.
The text string is structured like this X#2016-06-17#7483631#2016-06-27#2#167890##920, it's split up by #. I want to find 6th text block, 167890 in this case.
Is there a simple way to do this?
Perhaps with a little XML
Example
Declare #YourTable table (SomeCol varchar(500))
Insert Into #YourTable values
('X#2016-06-17#7483631#2016-06-27#2#167890##920')
Select SomeCol
,Pos6 = cast('<x>' + replace(A.SomeCol,'#','</x><x>')+'</x>' as xml).value('/x[6]','varchar(50)')
From #YourTable A
Returns
SomeCol Pos6
X#2016-06-17#7483631#2016-06-27#2#167890##920 167890
Create a SPLIT function, returning each part with an index like below:
CREATE FUNCTION [dbo].[StringSplit_WithIndex] (#str_in VARCHAR(8000),#separator VARCHAR(4) ) RETURNS #strtable TABLE (strval VARCHAR(8000),rn INT IDENTITY(1,1)) AS
BEGIN
DECLARE
#Occurrences INT,
#Counter INT,
#tmpStr VARCHAR(8000)
SET #Counter = 0
IF SUBSTRING(#str_in,LEN(#str_in),1) <> #separator
SET #str_in = #str_in + #separator
SET #Occurrences = (DATALENGTH(REPLACE(#str_in,#separator,#separator+'#')) - DATALENGTH(#str_in))/ DATALENGTH(#separator)
SET #tmpStr = #str_in
WHILE #Counter <= #Occurrences
BEGIN
SET #Counter = #Counter + 1
INSERT INTO #strtable
VALUES ( SUBSTRING(#tmpStr,1,CHARINDEX(#separator,#tmpStr)-1))
SET #tmpStr = SUBSTRING(#tmpStr,CHARINDEX(#separator,#tmpStr)+1,8000)
IF DATALENGTH(#tmpStr) = 0
BREAK
END
RETURN
END
Then, all you need to use the "rn" field after splitting like:
DECLARE #s VARCHAR(255) = 'X#2016-06-17#7483631#2016-06-27#2#167890##920'
SELECT *
FROM [StringSplit_WithIndex](#s,'#')
WHERE rn=6
I am using SQL Server 2008 R2. I am having some problems finding an effective coding pattern for SQL which supports code re-usability as well as flexibility. By re-usability, what I mean is keeping SQL queries in Stored Procedures and User Defined Functions.
Now, if I choose Stored Procedures, I will be sacrificing its usability in a query directly. If I choose User Defined Functions, I won't be able to use DML statements.
For example, suppose I created a Stored Procedures which inserts one contact record. Now, if I am having a table which can act as a source of multiple contact records, all I am left with are either WHILE loops or CURSORs, which is clearly not a recommended option, due to its performance drawbacks. And due to the fact that DML statements are not allowed in User Defined Functions, I simply cannot use them for this purpose.
Although, If I am not concerned with code re-usability, then instead of using Stored Procedures I can surely use same set of queries again and again to avoid while loops.
What pattern should I follow?
Here is a similar Stored Procedures:-
ALTER Proc [dbo].[InsertTranslationForCategory]
(
#str nvarchar(max),
#EventId int,
#CategoryName NVarchar(500),
#LanguageId int,
#DBCmdResponseCode Int Output,
#KeyIds nvarchar(max) Output
)as
BEGIN
DECLARE #XmlData XML
DECLARE #SystemCategoryId Int
DECLARE #CategoryId Int
Declare #Counter int=1
Declare #tempCount Int
Declare #IsExists int
Declare #TranslationToUpdate NVarchar(500)
Declare #EventName Varchar(200)
declare #Locale nvarchar(10)
declare #Code nvarchar(50)
declare #KeyName nvarchar(200)
declare #KeyValue nvarchar(500)
select #Locale=locale from languages where languageid = #LanguageId
SET #DBCmdResponseCode = 0
SET #KeyIds = ''
select #EventName = eventName from eventLanguages
where eventID = #EventId
--BEGIN TRY
Select #SystemCategoryId=CategoryId from SystemCategories where Name=rtrim(ltrim(#CategoryName))
Select #CategoryId=CategoryId from Categories where Name=rtrim(ltrim(#CategoryName)) and EventId=#EventId
if (#str='deactivate')
Begin
Delete from Codetranslation where CategoryId=#CategoryId
Update Categories set [Status]=0, Isfilter=0 where CategoryId=#CategoryId and Eventid=#EventId
Set #DBCmdResponseCode=2
return
End
set #XmlData=cast(#str as xml)
DECLARE #temp TABLE
(
Id int IDENTITY(1,1),
Code varchar(100),
Translation varchar(500),
CategoryId int
)
Insert into #temp (Code,Translation,CategoryId)
SELECT
tab.col.value('#Code', 'varchar(200)'),
tab.col.value('#Translation', 'varchar(500)'),#SystemCategoryId
FROM #XmlData.nodes('/Data') AS tab (col)
select #tempCount=Count(*) from #temp
if(IsNull(#CategoryId,0)>0)
Begin
While (#Counter <= #tempCount)
Begin
Select #IsExists= count(sc.categoryid) from #temp t Inner Join SystemCodetranslation sc
On sc.categoryid=t.CategoryId
where ltrim(rtrim(sc.code))=ltrim(rtrim(t.code)) and ltrim(rtrim(sc.ShortTranslation))=ltrim(rtrim(t.Translation))
and t.Id= #Counter
print #IsExists
Select #Code = Code , #KeyValue = Translation from #temp where id=#counter
set #KeyName = ltrim(rtrim(#EventName)) + '_' + ltrim(rtrim(#CategoryName)) + '_' + ltrim(rtrim(#Code)) + '_LT'
exec dbo.AddUpdateKeyValue #EventId,#Locale, #KeyName,#KeyValue,NULL,12
select #KeyIds = #KeyIds + convert(varchar(50),keyvalueId) + ',' from dbo.KeyValues
where eventid = #EventId and keyname = #KeyName and locale = #Locale
set #KeyName = ''
set #KeyValue = ''
Set #Counter= #Counter + 1
Set #IsExists=0
End
End
--- Inser data in Codetranslation table
if(isnull(#CategoryId,0)>0)
Begin
print #CategoryId
Delete from codetranslation where categoryid=#CategoryId
Insert into codetranslation (CategoryId,Code,LanguageId,ShortTranslation,LongTranslation,SortOrder)
SELECT
#CategoryId,
tab.col.value('#Code', 'varchar(200)'), #LanguageId,
tab.col.value('#Translation', 'varchar(500)'),
tab.col.value('#Translation', 'varchar(500)'),0
FROM #XmlData.nodes('/Data') AS tab (col)
Update Categories set [Status]=1 where CategoryId=#CategoryId and Eventid=#EventId
End
Set #DBCmdResponseCode=1
set #KeyIds = left(#KeyIds,len(#KeyIds)-1)
END
You can use table variable parameter for your user defined functions.
following code is an example of using table variable parameter in stored procedure.
CREATE TYPE IdList AS TABLE (Id INT)
CREATE PROCEDURE test
#Ids dbo.IdList READONLY
AS
Select *
From YourTable
Where YourTable.Id in (Select Id From #Ids)
End
GO
In order to execute your stored procedure use following format:
Declare #Ids dbo.IdList
Insert into #Ids(Id) values(1),(2),(3)
Execute dbo.test #Ids
Edit
In order to return Inserted Id, I don't use from Table Variable Parameter. I use following query sample for this purpose.
--CREATE TYPE NameList AS TABLE (Name NVarChar(100))
CREATE PROCEDURE test
#Names dbo.NameList READONLY
AS
Declare #T Table(Id Int)
Insert Into YourTable (Name)
OUTPUT Inserted.Id Into #T
Select Name
From #Names
Select * From #T
End
GO
This is the scenario:
My app will have the following:
A listbox (The checkbox property enabled) that will display a list of Something.
The user will select from the listbox (multiselect) by using the checkbox.
I will loop into All the checked items and store the ID's into an array. I will store the ID's into something like this separating the ID with a comma (1,2,3,4) and then I will use length -1 to delete the last comma.
How can I convert the string 1,2,3,4 into an integer type of data if my stored procedure is like this?
Select * from tblSomething Where ID in (1,2,3,4)
You can use the following SQL function.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[CommaSeparatedToString]
(
#psCSString VARCHAR(8000)
)
RETURNS #otTemp TABLE(sID VARCHAR(20))
AS
BEGIN
DECLARE #sTemp VARCHAR(50)
WHILE LEN(#psCSString) > 0
BEGIN
SET #sTemp = LEFT(#psCSString, ISNULL(NULLIF(CHARINDEX(',', #psCSString) - 1, -1),
LEN(#psCSString)))
SET #psCSString = SUBSTRING(#psCSString,ISNULL(NULLIF(CHARINDEX(',', #psCSString), 0),
LEN(#psCSString)) + 1, LEN(#psCSString))
INSERT INTO #otTemp VALUES (#sTemp)
END
RETURN
END
And call in your stored procedure like
Select * from tblSomething
Where ID in (SELECT * FROM CommaSeparatedToString('1,2,3,4'))
You can use the
SELECT CAST(MyVarcharCol AS INT) FROM Table
SELECT CONVERT(INT, MyVarcharCol) FROM Table
refer this link
http://msdn.microsoft.com/en-us/library/ms187928.aspx
You need to create dynamic query for this
e.g you are getting list of values in #values paramter so prepare and run the dynamic query like this
DECLARE #query NVARCHAR(500)
DECLARE #values VARCHAR(200)
SET #values='1,2'
SET #query =N'Select * from tblSomething Where ID in ( ' + #values + ')'
SELECT #query
EXEC #Query
Use this function to split the value:
CREATE FUNCTION [dbo].[udfSplitCSV]
(
#String varchar (max),
#Delimiter varchar (10) = ','
)
RETURNS #ValueTable TABLE ([Row] int IDENTITY(1,1), [Value] varchar(max), [Length] int, [Duplicate] int NULL)
BEGIN
DECLARE #NextString varchar(max)
DECLARE #Pos int
DECLARE #NextPos int
IF #String IS NULL RETURN
--Initialize
SET #NextString = ''
SET #String = #String + #Delimiter
--Get position of first Comma
SET #Pos = charindex(#Delimiter,#String)
SET #NextPos = 1
--Loop while there is still a comma in the String
WHILE (#Pos <> 0)
BEGIN
SET #NextString = RTrim(LTrim(SubString(#String,1,#Pos - 1)))
INSERT INTO #ValueTable ([Value], [Length]) VALUES (#NextString, Len(#NextString))
SET #String = SubString(#String,#Pos+1,Len(#String))
SET #NextPos = #Pos
SET #Pos = CharIndex(#Delimiter,#String)
END
UPDATE #ValueTable
SET [Duplicate] = X.Duplicate
FROM #ValueTable VT
INNER JOIN (Select [Row], [Value], Row_Number() OVER (Partition By [Value] ORDER BY [Value], [Row]) as Duplicate FROM #ValueTable) X
ON X.[Row] = VT.[Row]
RETURN
END
-- Select * from dbo.udfSplitCSV('a , c b,c, a', ',')
When you are storing a bunch of IDs into the array, store with single quote.
so it will be ('1','2','3').
Then you no need to covert IDs into integer.
If I have a string with values like A,B,C,D,E,F, and I wanted to remove the last comma, is there a function or script I can use to do that?
The below example will trim off the last char of a string but wont care if it's a comma or not
DECLARE #s VARCHAR(50)
SET #s = 'a,b,'
SELECT LEFT(#s, LEN(#s)-1)
If I'm understanding you additional question correctly, I believe you want to archive something like the below...
DECLARE #b TABLE
(
[stuff] VARCHAR(2)
)
INSERT INTO #b VALUES('c')
DECLARE #s VARCHAR(MAX)
SET #s = 'a,b,c'
SELECT [stuff]
FROM #b b
INNER JOIN dbo.list(#s) lst
ON lst.val = b.[stuff]
CREATE function [dbo].[list] ( #list VARCHAR(MAX) )
RETURNS #list_table TABLE ([val] VARCHAR(20))
AS
BEGIN
DECLARE #index INT,
#start_index INT,
#val VARCHAR(20)
SELECT #index = 1
SELECT #start_index = 1
WHILE #index <= DATALENGTH(#list)
BEGIN
IF SUBSTRING(#list,#index,1) = ','
BEGIN
SELECT #val = SUBSTRING(#list, #start_index, #index - #start_index )
INSERT #list_table ([val]) VALUES (#val)
SELECT #start_index = #index + 1
END
SELECT #index = #index + 1
END
SELECT #val = SUBSTRING(#list, #start_index, #index - #start_index )
INSERT #list_table ([val]) VALUES (#val)
RETURN
END
The function just splits up the input string into rows in a table with a column "val" - this means you can then pass in a comma delimited string and use it to filter another table.