SQL multi save without using loop/ cursor - sql

I have a requirement where from a string of int[] I need to insert all the values of this array into DB.
I have tried this solution and it works fine.
To achieve this I have converted the int[] to XML in C#, and in SP used this XML variable to fill a table variable and looped over this table variable to do the insert.
Is there any way to avoid the while loop and insert multiple values comma separated string into the table ?
Below is the code :
DECLARE #CatTable TABLE(RowID int not null primary key identity(1,1), ID int)
DECLARE #RowsToProcess int
DECLARE #CurrentRow int
INSERT INTO #Table
SELECT tbl.colname.value('text()[1]','int') AS Id
FROM #IdsList.nodes('/List/CIds') tbl(colname);
SET #RowsToProcess=##ROWCOUNT
SET #CurrentRow=0
WHILE #CurrentRow<#RowsToProcess --- **How to avoid this loop and do the insert ?**
BEGIN
SET #CurrentRow=#CurrentRow+1
INSERT INTO tblRealtable (id, anotherId)
SELECT ID ,#AnotherID FROM #Table
WHERE RowID=#CurrentRow
END
enD
END

Aren't you just after this?
INSERT INTO dbo.tblRealtable (id, anotherId)
SELECT tbl.colname.value('text()[1]','int') AS Id
#AnotherID
FROM #IdsList.nodes('/List/CIds') tbl(colname);

Related

How to store multiple values in a SQL Server variable

I want to store values from a SELECT statement into a variable which is capable of holding more than one value because my SELECT statement returns multiple values of type INT. This is how my SP looks like so far.
ALTER PROCEDURE "ESG"."SP_ADD"
AS
BEGIN
DECLARE #Id table(identifiers VARCHAR);
INSERT INTO #Id (identifiers) VALUES('axaa1aaa-aaaa-a5aa-aaaa-aa8aaaa9aaaa');
INSERT INTO #Id (identifiers) VALUES('bxbb1bbb-bbbb-b5bb-bbb4-bb8bbbb9bbbf');
DECLARE #tranID INT = (SELECT
DOCUMENT_SET_.DOCUMENT_SET_TRANSACTION_ID
FROM DOCUMENT_SET_TRANSACTION
WHERE DOCUMENT_SET_TRANSACTION.IDENTIFIER IN (SELECT identifiers FROM #Id));
END
Variable #tranID should be a list or an array to hold the ids. Is it possible to do it SQL Server?
You can declare a variable of type table
DECLARE #tblTrans TABLE (
tranID INT
);
INSERT INTO #tblTrans
SELECT DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID
FROM ESG.DOCUMENT_SET_TRANSACTION
WHERE DOCUMENT_SET_TRANSACTION.IDENTIFIER
IN (SELECT identifiers FROM #envelopeId);
Depending on what you want to do with the values after this, you could declare a cursor to loop through them or select straight from the variable.
You could also look into using a temporary table depending on what scope you need.
Try this, only take the firs row of example. Do u try this?
select DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID,
(STUFF((SELECT '-' + convert(varchar(max),DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID)
FROM ESG.DOCUMENT_SET_TRANSACTION
FOR XML PATH ('')), 1, 2, '')) AS example
FROM ESG.DOCUMENT_SET_TRANSACTION

Select row just inserted without using IDENTITY column in SQL Server 2012

I have a bigint PK column which is NOT an identity column, because I create the number in a function using different numbers. Anyway, I am trying to save this bigint number in a parameter #InvID, then use this parameter later in the procedure.
ScopeIdentity() is not working for me, it saved Null to #InvID, I think because the column is not an identity column. Is there anyway to select the record that was just inserted by the procedure without adding an extra ID column to the table?
It would save me a lot of effort and work if there is a direct way to select this record and not adding an id column.
insert into Lab_Invoice(iID, iDate, iTotal, iIsPaid, iSource, iCreator, iShiftID, iBalanceAfter, iFileNo, iType)
values (dbo.Get_RI_ID('True'), GETDATE(),
(select FilePrice from LabSettings), 'False', #source, #user, #shiftID, #b, #fid, 'Open File Invoice');
set #invID = CAST(scope_identity() AS bigint);
P.S. dbo.Get_RI_ID('True') a function returns a bigint.
Why don't you use?
set #invId=dbo.Get_RI_ID('True');
insert into Lab_Invoice(iID,iDate,iTotal,iIsPaid,iSource,iCreator,iShiftID,iBalanceAfter,iFileNo,iType)
values(#invId,GETDATE(),(select FilePrice from LabSettings),'False',#source,#user,#shiftID,#b,#fid,'Open File Invoice');
You already know that big id value. Get it before your insert statement then use it later.
one way to get inserted statement value..it is not clear which value you are trying to get,so created some example with dummy data
create table #test
(
id int
)
declare #id table
(
id int
)
insert into #test
output inserted.id into #id
select 1
select #invID=id from #id

SQL Merge Statement - Output into a scalar variable (SQL Server)

I'm getting my head around the MERGE statement in SQL server. I generally use it to insert/update a single row, which I realise isn't the only use, but it's something I seem to do quite often.
But what happens if you want to insert a value of 1, or update to increment the value and output the incremented value eg:
CREATE TABLE [Counter] (
[Key] VARCHAR(255) NOT NULL PRIMARY KEY,
[Value] INT NOT NULL
);
DECLARE #paramKey VARCHAR(255);
SET #paramKey = 'String';
MERGE [Counter] AS targt
USING (Values(#paramKey)) AS source ([Key])
ON (targt.[Key] = source.[Key])
WHEN MATCHED THEN
UPDATE SET Value = Value +1
WHEN NOT MATCHED THEN
INSERT ([Key], Value)
VALUES (source.[Key], 1);
-- but now I want the new value!
Is there a way of doing this? I notice the output clause in https://msdn.microsoft.com/en-gb/library/bb510625.aspx but it doesn't seem to work with scalars (I could output to a single row-ed table variable but that seems wrong):
-- using table variables but seems
DECLARE #paramKey VARCHAR(255), #value int;
SET #paramKey = 'String'
DECLARE #Tab table (
[Value] INT
)
MERGE Counter AS targt
USING (Values(#paramKey)) AS source ([Key])
ON (targt.[Key] = source.[Key])
WHEN MATCHED THEN
UPDATE SET Value = Value +1
WHEN NOT MATCHED THEN
INSERT ([Key], Value)
VALUES (source.[Key], 1)
OUTPUT inserted.[Value] INTO #Tab;
-- can now use #Tab as a single rowed table variable
Is there a better option?

inserting values from on table to another in sql server 2008 with one field should be incremented

declare #cid int
set #cid=(select ISNULL(MAX(cid),0)+1 from CustInfo)
insert into CustInfo(CID,CTypeId,CustNo,Regdate,
DOB,CCertID,CCertNo,CompId,PostedBy,PostedOn)
(select #cid,1,0,'2012-9-10',
dob,ccertid,ccertno,0,null,null
from updateCust3)
I have used above code to insert values from table updateCust3 to table UpdateCustInfo.
In this case the CID field should be incremented by one at each insert. I have used the above code but the cid doesn't seem to increase so the error is duplicate value for the primary key. So how can I increase the value of cid? Since the change in table property is not allowed I cannot use identity property.
try this:
declare #cid int
set #cid=(select ISNULL(MAX(cid),0)+1 from CustInfo)
insert into CustInfo(CID,CTypeId,CustNo,Regdate,
DOB,CCertID,CCertNo,CompId,PostedBy,PostedOn)
select #cid+row_number() over (order by (select 0)),1,0,'2012-9-10',
dob,ccertid,ccertno,0,null,null
from updateCust3)
Edit: As MikaelEriksson mentioned in the comment, this has the risk, if you users are simultaneously trying to update the table, it will error out..
have used a temp table to demonstrate. This is a better way to work to avoid errors when used by multiple users
DECLARE #Table TABLE
(
CTypeId INT identity (1,1)
,CustNo int
,DOB datetime
,Regdate datetime
,CCertID int
,CCertNo int
,CompId int
,PostedBy varchar(100)
,PostedOn datetime
)
INSERT #Table
select 1,0,'2012-9-10',
dob,ccertid,ccertno,0,null,null
from updateCust3

SQL How to find if all values from one field exist in another field in any order

I am trying to match data from an external source to an in house source. For example one table would have a field with a value of "black blue" and another table would have a field with a value of "blue black". I am trying to figure out how to check if all individual words in the first table are contained in a record the 2nd table in any order. It's not always two words that need to be compared it could be 3 or 4 as well. I know I could use a cursor and build dynamic sql substituting the space with the AND keywod and using the contains function but I'm hoping not to have to do that.
Any help would be much appreciated.
Try doing something like this: Split the data from the first table on the space into a temporary table variable. Then use CHARINDEX to determine if each word is contained in the second table's record. Then just do this for each word in the first record and if the count is the same as the successful checks then you know every word from the first record is used in the second.
Edit: Use a Split function such as:
CREATE FUNCTION dbo.Split (#sep char(1), #s varchar(512))
RETURNS table
AS
RETURN (
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(#sep, #s, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT pn,
SUBSTRING(#s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
FROM Pieces
)
Here's another method you could try, you could sample some simple attributes of your strings such as, length, number of spaces, etc.; then you could use a cross-join to create all of the possible string match combinations.
Then within your where-clause you can sort by matches, the final piece of which in this example is a check using the patindex() function to see if the sampled piece of the first string is in the second string.
-- begin sample table variable set up
declare #s table(
id int identity(1,1)
,string varchar(255)
,numSpace int
,numWord int
,lenString int
,firstPatt varchar(255)
);
declare #t table(
id int identity(1,1)
,string varchar(255)
,numSpace int
,numWord int
,lenString int
);
insert into #t(string)
values ('my name');
insert into #t(string)
values ('your name');
insert into #t(string)
values ('run and jump');
insert into #t(string)
values ('hello my name is');
insert into #s(string)
values ('name my');
insert into #s(string)
values ('name your');
insert into #s(string)
values ('jump and run');
insert into #s(string)
values ('my name is hello');
update #s
set numSpace = len(string)-len(replace(string,' ',''));
update #s
set numWord = len(string)-len(replace(string,' ',''))+1;
update #s
set lenString = len(string);
update #s
set firstPatt = rtrim(substring(string,1,charindex(' ',string,0)));
update #t
set numSpace = len(string)-len(replace(string,' ',''));
update #t
set numWord = len(string)-len(replace(string,' ',''))+1;
update #t
set lenString = len(string);
-- end sample table variable set up
-- select all combinations of strings using a cross join
-- and sort the entries in your where clause
-- the pattern index checks to see if the sampled string
-- from the first table variable is in the second table variable
select *
from
#s s cross join #t t
where
s.numSpace = t.numspace
and s.numWord = t.numWord
and s.lenString = t.lenString
and patindex('%'+s.firstPatt+'%',t.string)>0;