The best method to update every row in SQL Server - sql

I have code like this to create random table: (http://dba.fyicenter.com/faq/sql_server/Creating_a_Large_Table_with_Random_Data_for_Indexes.html)
-- Create a table with primary key
CREATE TABLE fyi_random
(
id INT,
rand_integer INT,
rand_number numeric(18,9),
rand_datetime DATETIME,
rand_string VARCHAR(80)
);
-- Insert rows with random values
DECLARE #row INT;
DECLARE #string VARCHAR(80), #length INT, #code INT;
SET #row = 0;
WHILE #row < 100000
BEGIN
SET #row = #row + 1;
-- Build the random string
SET #length = ROUND(80*RAND(),0);
SET #string = '';
WHILE #length > 0
BEGIN
SET #length = #length - 1;
SET #code = ROUND(32*RAND(),0) - 6;
IF #code BETWEEN 1 AND 26
SET #string = #string + CHAR(ASCII('a')+#code-1);
ELSE
SET #string = #string + ' ';
END
-- Ready for the record
SET NOCOUNT ON;
INSERT INTO fyi_random
VALUES (#row,
ROUND(2000000*RAND()-1000000,0),
ROUND(2000000*RAND()-1000000,9),
CONVERT(DATETIME, ROUND(60000*RAND() - 30000, 9) ),
#string)
END
PRINT 'Rows inserted: '+CONVERT(VARCHAR(20),#row);
GO
I want to update every row (for example update column rand_string with some new random string). What is the best method? When I'm trying to do this by while loop performance decreases with increasing rows:
...
SET NOCOUNT ON;
UPDATE random_data
SET rand_string = #string
WHERE id = #row;
I also tried to use cursor statement and it's better but why while loop is so slow? And is there another way to do this better?

If you want to update every row in a table then just omit the where clause in the update statement.

Related

SQL server transfer column from one table to another

I am trying to transfer data from a column from one table to another, both columns are with unique identifiers and when i transfer the data it is copying the column after the end of the data of the second table. After the end of the other column of the second table (I am inserting first random integers in the first column and then I want to copy the information from another table in the same database and it is starting after the 135th row (I add 135 rows with random ints)). First table name : carBrand and column name model_id - second table name Cars11, model_idss - or whatever is the name...
THE QUESTION IS WHY is it inputting the iformation after the first input - example - i am inputting 135 random ints and after that i am trying to copy the information from the other table and when i am pasting it, the information is pasted after the 136th to the 270th sign
My query is looking like this for the new table
DECLARE #Min_Value AS int
SET #Min_Value= 15000
DECLARE #Max_Value AS int
SET #Max_Value = 1000000
DECLARE #n AS int
SET #n = 135
BEGIN TRANSACTION
DECLARE #uid uniqueidentifier
SET #uid = NEWID()
DECLARE #i AS int
SET #i = 1
WHILE #i <= #n BEGIN INSERT INTO Cars11([Model_prices]) VALUES(FLOOR(RAND(CHECKSUM(#uid))*(#Max_Value - #Min_Value +1) + #Min_Value)) SET #i += 1 SET #uid = NEWID() END COMMIT TRANSACTION
INSERT INTO Cars11(model_idss)
SELECT model_id
FROM carBrand
WHERE model_id <= 135;
It would be easier to parse your query if you used the code sample block (ctrl-k)
You need to do an update instead of insert for the second insert into Cars11.
Update changes already existing records, Insert creates new records.
Something like this:
DECLARE #Min_Value AS int
SET
#Min_Value = 15000
DECLARE #Max_Value AS int
SET
#Max_Value = 1000000
DECLARE #n AS int
SET
#n = 135
BEGIN TRANSACTION
DECLARE #uid uniqueidentifier
SET
#uid = NEWID()
DECLARE #i AS int
SET
#i = 1 WHILE #i <= #n
BEGIN
INSERT INTO
Cars11([Model_prices])
VALUES
(
FLOOR(
RAND(CHECKSUM(#uid)) *(#Max_Value - #Min_Value + 1) + #Min_Value
)
)
SET
#i + = 1
SET
#uid = NEWID()
END
COMMIT TRANSACTION
UPDATE Cars11
Set model_idss = (Select model_id FROM carBrand WHERE Cars11.model_idss = carBrand.model_id and carBrand.model_id <= 135));
Here are some other options for updating a column based on a query result

how to pass more values for a single parameter in storedprocedure in sql server

MY text:-
CREATE proc usp_delete
#tranid int
as
begin
delete from customer where tranid in(#tranid)
end
Note:- I want to delete records more than 1 records through this stored procedure like:- if I pass 1,2,3,4,5,6 that time all 6 records should be deleted
You can use table-valued parameter for that you need to declare that
CREATE TYPE EntityId AS TABLE
( Id INT )
GO
CREATE PROCEDURE usp_delete
#tranid EntityId READONLY
AS
BEGIN
DELETE c
FROM customer c
JOIN #tranid t ON t.Id=c.tranid
END
For Executing with TVP declare a varible of type and pass it to the stored procedure
DECLARE #entityId EntityId
INSERT INTO #entityId
VALUES(1),(2),(3),(4),(5)
EXEC usp_delete #entityId
In later version of SQL Server you can use STRING_SPLIT to convert a delimited list into individual values and then join to your table using CROSS APPLY.
CREATE PROC usp_delete #tranid VARCHAR(MAX) AS
BEGIN
DELETE c
FROM customer c
CROSS APPLY STRING_SPLIT(#tranid, ',')
WHERE c.tranid = value
END
GO
EXEC usp_delete '2,3,4'
In older version you can write your own table-valued function to convert a delimited string into a result set.
CREATE function [dbo].[delimited_string_to_table] (
#delimiter char(1)
, #string text
)
returns #table table (
seqnbr int not null
, string varchar(255) not null
)
as
begin
declare #pos int
declare #textpos int
declare #chunklen smallint
declare #tmpstr varchar(8000)
declare #leftover varchar(8000)
declare #tmpval varchar(8000)
declare #seq int = 1
set #textpos = 1
set #leftover = ''
while #textpos <= datalength(#string)
begin
set #chunklen = 8000 - datalength(#leftover) / 2
set #tmpstr = #leftover + substring(#string, #textpos, #chunklen)
set #textpos = #textpos + #chunklen
set #pos = charindex(#delimiter, #tmpstr)
while #pos > 0
begin
set #tmpval = ltrim(rtrim(left(#tmpstr, #pos - 1)))
insert #table (seqnbr, string) values(#seq, #tmpval)
set #tmpstr = substring(#tmpstr, #pos + 1, len(#tmpstr))
set #pos = charindex(#delimiter, #tmpstr)
set #seq = #seq + 1
end
set #leftover = #tmpstr
end
if len(rtrim(ltrim(#leftover))) != 0
insert #table(seqnbr, string) values (#seq, ltrim(rtrim(#leftover)))
return
end
GO
Which would change the example to look like this:
CREATE PROC usp_delete #tranid VARCHAR(MAX) AS
BEGIN
DELETE c
FROM customer c
JOIN dbo.delimited_string_to_table(',', #tranid)
ON c.tranid = string
END
GO

remove numeric values in data using sql

my data is :
Id Case ID#
1. QCCR1A105369, QCCR1A104986 ,QCCR1A103717
2. QCIM1A106902,4613410733 QCIM1A106902; 4613344523 QCIM1A105842; 4614004212 QCIM1A106580; 4614060189 QCIM1A106676
3. QCCR1D93616, QCCR1D92488, QCCR1D58461
4. QCCR1B40216 .... ,QCCR1B39080, QCCR1B40216, QCCR1B39745, QCCR1B38463 , QCCR1B38618, QCCR1B38619, QCCR1B38620, QCCR1B38621, QCCR1B38622, QCCR1B38465, QCCR1B38623
5. QCCR2A30221 QCCR2A30223 QCCR2A30222 QCIM2A30416
My output will be Id 1,3,4,5. I want only that rows, which have starting value QC not any numeric value. For ID 2 you can see there are some numeric values, please tell me how can I achieve it.
You could use a table valued function to split your value by a delimiter like this:
CREATE FUNCTION [dbo].[Split]
(
#ItemList NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #ItemTable TABLE (Item VARCHAR(250))
AS
BEGIN
DECLARE #tempItemList NVARCHAR(MAX)
SET #tempItemList = #ItemList
DECLARE #i INT
DECLARE #Item NVARCHAR(4000)
SET #i = CHARINDEX(#delimiter, #tempItemList)
WHILE (LEN(#tempItemList) > 0)
BEGIN
IF #i = 0
SET #Item = #tempItemList
ELSE
SET #Item = LEFT(#tempItemList, #i - 1)
INSERT INTO #ItemTable(Item) VALUES(#Item)
IF #i = 0
SET #tempItemList = ''
ELSE
SET #tempItemList = RIGHT(#tempItemList, LEN(#tempItemList) - #i)
SET #i = CHARINDEX(#delimiter, #tempItemList)
END
RETURN
END
Then this query returns the expected result:
SELECT t.*
FROM dbo.TableName t
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.Split(t.CaseID, ',') split
WHERE NOT LEFT(LTRIM(split.Item), 2) = 'QC'
OR ISNUMERIC(split.Item) = 1
)
Demo with your sample data. But in general you should avoid multiple values in one column. Instead store it in separate rows in a linked table. That's called database normalization.

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

Sql query checking condition before insert row

I have a table called dbo.Tbl_ActivityInformations and the data look like
Activityid activitymaxcount Activityusedcount
1 10 9
2 10 7
3 15 15
And another table called Tbl_AttendeeInformations and the data look like
AttendedID AssID ActivityID
13 123456 1,2
14 123457 1,3
In the Tbl_AttendeeInformations table data will be inserted as new row from page and in the ActivityInformations table Activityusedcount column incremented by one for appropriate activityID.
Now I want to check before inserting a row into AttendeeInformations that Activityusedcount < activitymaxcount using ActivityID. If the condition is satisfied then only it will allow to insert otherwise it should rollback. I have function named SplitString to split ActivityID in Tbl_AttendeeInformations.
This is the code for SplitString
create FUNCTION dbo.SplitString(#FormattedString varchar(8000),#Delimitter char(1))
returns #retResults TABLE(Value varchar(8000),Rownumber int)
as
BEGIN
DECLARE #SearchString as varchar(8000)
DECLARE #AssignString as varchar(8000)
DECLARE #Index int
DECLARE #Count int
set #SearchString = #FormattedString
set #AssignString= ''
set #Count = 0
while(len(#SearchString) > 0 )
begin
SET #Index = CHARINDEX(#Delimitter,#SearchString, 0)
set #Count = #Count + 1
if #Index = 0
begin
INSERT INTO #retResults
values( #SearchString,#Count)
set #SearchString = ''
continue
end
set #AssignString = SUBSTRING(#SearchString,1, #Index - 1 )
INSERT INTO #retResults values
(#AssignString,#Count)
SET #SearchString = (select SUBSTRING(#SearchString, #Index + 1, LEN(#SearchString) - #Index ))
end
return
END
Please do help.
Pseudocode to show an idea:
INSERT INTO AttendeeInformations
SELECT act.*
FROM ActivityInformations act
INNER JOIN AttendeeInformations at ON act.ActivityID = at.ActivityID
WHERE act.Activityusedcount < act.activitymaxcount