How can i replace %20 to space in a specific column? - tsql

I do have a table (fund) that has a column named 'fText'.
This table has around 700k data and some data randomly has some '%20' in middle of string. The Column type is varchar(5000).
For example in one row, I have 'Today%20is%2010/3/2019%20%20'.
The '%20' can be anywhere in ftext column. is there anyway to clean up all 700k data with Update statement?
I need a update statement that can change such text to below. (Replace all %20 to space ' ')
Today is 10/3/2019

Check this -
DECLARE #Sample VARCHAR(100)='Today%20is%2010/3/2019%20%20'
SELECT #Sample AS INPUT,LTRIM(RTRIM(REPLACE(#Sample,'%20',' ')))
For Scenario - Use this
IF OBJECT_ID('TEMPDB..#Fund') IS NOT NULL
DROP TABLE #Fund
Create table #Fund
(
ftext varchar(5000)
)
insert into #Fund(ftext)
values
('Today%20is%2010/3/2019%20%20')
--SELECT LTRIM(RTRIM(REPLACE(ftext,'%20',' '))) FROM #Fund
UPDATE #Fund SET ftext=LTRIM(RTRIM(REPLACE(ftext,'%20',' '))) WHERE ftext LIKE '%[%]20%'
SELECT ftext FROM #Fund

#forpas helped me and II got this answer :)
Thank you
The answer:
begin transaction;
update ff_fundinfo
set fundtext=replace(fundtext,'%20',' ') where fundtext like '%[%]20%'

Related

Concatenate string instead of just replacing it

I have a table with standard columns where I want to perform regular INSERTs.
But one of the columns is of type varchar with special semantics. It's a string that's supposed to behave as a set of strings, where the elements of the set are separated by commas.
Eg. if one row has in that varchar column the value fish,sheep,dove, and I insert the string ,fish,eagle, I want the result to be fish,sheep,dove,eagle (ie. eagle gets added to the set, but fish doesn't because it's already in the set).
I have here this Postgres code that does the "set concatenation" that I want:
SELECT string_agg(unnest, ',') AS x FROM (SELECT DISTINCT unnest(string_to_array('fish,sheep,dove' || ',fish,eagle', ','))) AS x;
But I can't figure out how to apply this logic to insertions.
What I want is something like:
CREATE TABLE IF NOT EXISTS t00(
userid int8 PRIMARY KEY,
a int8,
b varchar);
INSERT INTO t00 (userid,a,b) VALUES (0,1,'fish,sheep,dove');
INSERT INTO t00 (userid,a,b) VALUES (0,1,',fish,eagle')
ON CONFLICT (userid)
DO UPDATE SET
a = EXCLUDED.a,
b = SELECT string_agg(unnest, ',') AS x FROM (SELECT DISTINCT unnest(string_to_array(t00.b || EXCLUDED.b, ','))) AS x;
How can I achieve something like that?
Storing comma separated values is a huge mistake to begin with. But if you really want to make your life harder than it needs to be, you might want to create a function that merges two comma separated lists:
create function merge_lists(p_one text, p_two text)
returns text
as
$$
select string_agg(item, ',')
from (
select e.item
from unnest(string_to_array(p_one, ',')) as e(item)
where e.item <> '' --< necessary because of the leading , in your data
union
select t.item
from unnest(string_to_array(p_two, ',')) t(item)
where t.item <> ''
) t;
$$
language sql;
If you are using Postgres 14 or later, unnest(string_to_array(..., ',')) can be replace with string_to_table(..., ',')
Then your INSERT statement gets a bit simpler:
INSERT INTO t00 (userid,a,b) VALUES (0,1,',fish,eagle')
ON CONFLICT (userid)
DO UPDATE SET
a = EXCLUDED.a,
b = merge_lists(excluded.b, t00.b);
I think I was only missing parentheses around the SELECT statement:
INSERT INTO t00 (userid,a,b) VALUES (0,1,',fish,eagle')
ON CONFLICT (userid)
DO UPDATE SET
a = EXCLUDED.a,
b = (SELECT string_agg(unnest, ',') AS x FROM (SELECT DISTINCT unnest(string_to_array(t00.b || EXCLUDED.b, ','))) AS x);

Make duplicate row in Postgresql

I am writing migration script to migrate database. I have to duplicate the row by incrementing primary key considering that different database can have n number of different columns in the table. I can't write each and every column in query. If i simply just copy the row then, I am getting duplicate key error.
Query: INSERT INTO table_name SELECT * FROM table_name WHERE id=255;
ERROR: duplicate key value violates unique constraint "table_name_pkey"
DETAIL: Key (id)=(255) already exist
Here, It's good that I don't have to mention all column names. I can select all columns by giving *. But, same time I am also getting duplicate key error.
What's the solution of this problem? Any help would be appreciated. Thanks in advance.
If you are willing to type all column names, you may write
INSERT INTO table_name (
pri_key
,col2
,col3
)
SELECT (
SELECT MAX(pri_key) + 1
FROM table_name
)
,col2
,col3
FROM table_name
WHERE id = 255;
Other option (without typing all columns , but you know the primary key ) is to CREATE a temp table, update it and re-insert within a transaction.
BEGIN;
CREATE TEMP TABLE temp_tab ON COMMIT DROP AS SELECT * FROM table_name WHERE id=255;
UPDATE temp_tab SET pri_key_col = ( select MAX(pri_key_col) + 1 FROM table_name );
INSERT INTO table_name select * FROM temp_tab;
COMMIT;
This is just a DO block but you could create a function that takes things like the table name etc as parameters.
Setup:
CREATE TABLE public.t1 (a TEXT, b TEXT, c TEXT, id SERIAL PRIMARY KEY, e TEXT, f TEXT);
INSERT INTO public.t1 (e) VALUES ('x'), ('y'), ('z');
Code to duplicate values without the primary key column:
DO $$
DECLARE
_table_schema TEXT := 'public';
_table_name TEXT := 't1';
_pk_column_name TEXT := 'id';
_columns TEXT;
BEGIN
SELECT STRING_AGG(column_name, ',')
INTO _columns
FROM information_schema.columns
WHERE table_name = _table_name
AND table_schema = _table_schema
AND column_name <> _pk_column_name;
EXECUTE FORMAT('INSERT INTO %1$s.%2$s (%3$s) SELECT %3$s FROM %1$s.%2$s', _table_schema, _table_name, _columns);
END $$
The query it creates and runs is: INSERT INTO public.t1 (a,b,c,e,f) SELECT a,b,c,e,f FROM public.t1. It's selected all the columns apart from the PK one. You could put this code in a function and use it for any table you wanted, or just use it like this and edit it for whatever table.

IF Exists doesn't seem to work for a Table Drop if already exists

Was getting this error each and every time tried to execute a DROP Table if exists
Step 1: Created a Table
CREATE TABLE Work_Tables.dbo.Drop_Table_Test (RowID INT IDENTITY(1,1), Data VARCHAR(50))
INSERT INTO Work_Tables.dbo.Drop_Table_Test
SELECT 'Test' UNION
SELECT 'Test1' UNION
SELECT 'Test2' UNION
SELECT 'Test3'
Step 2: Wrote a IF Exists block to check if the Table exists.
IF EXISTS (SELECT 1 FROM Work_Tables.dbo.SysObjects WHERE NAME LIKE 'Drop_Table_Test' AND XType = 'U')
BEGIN
PRINT 'IN'
DROP TABLE Work_Tables.dbo.Drop_Table_Test
END
CREATE TABLE Work_Tables.dbo.Drop_Table_Test (RowID INT IDENTITY(1,1), Data VARCHAR(50), NAME VARCHAR(20), PreCheck INT)
INSERT INTO Work_Tables.dbo.Drop_Table_Test (Data, Name, PreCheck)
SELECT 'Test','SRK',1 UNION
SELECT 'Test1','Daya',2 UNION
SELECT 'Test2','Dinesh',3 UNION
SELECT 'Test3','Suresh',4
On running the Step 2 Code its obvious the Table has to be Dropped and recreated with the same name but it didn't even enter the Begin End block.
I feel that its because have added few more columns in the second try, but still not clear why it should have problems as we are to DROP the table.
You can not drop and create the same table in the same batch in SQL Server.
Break your code up into separate batches so the table can be dropped before you try and recreate it. Add GO after END in your BEGIN / END statement.
IF EXISTS (SELECT 1 FROM Work_Tables.dbo.SysObjects WHERE NAME LIKE 'Drop_Table_Test' AND XType = 'U')
BEGIN
PRINT 'IN'
DROP TABLE Work_Tables.dbo.Drop_Table_Test
END
GO --Add this...
....
Straight from Microsoft's Documentation:
DROP TABLE and CREATE TABLE should not be executed on the same table in the same batch. Otherwise an unexpected error may occur.
You can try to use this syntax:
IF OBJECT_ID('dbo.Drop_Table_Test', 'U') IS NOT NULL
DROP TABLE dbo.Drop_Table_Test;
IF EXISTS will drop the table only when your table Drop_Table_Test does not contain any row. In case if it contains the data then it will not drop the table.

Is it possible to pass a sub-query for the Default Value when adding a new column to a table?

ALTER TABLE TABLENAME
ADD New_Col3 INT NOT NULL
CONSTRAINT CONSTRAINT_1 DEFAULT {DEFAULT_VALUE}
If i am adding a new column that is not null to an existing table, is there away i can pass a t-sql sub query to provide the column's default value? Or i can only update the new column with query result value in a separate statement?
The sub-query is like below
SELECT ID FROM dbo.Category WHERE CategoryName = N'Default Category'
I think you could clarify for us a bit more about what you're doing. I'm confused. This is all that I can think of...
DECLARE #sqlstring varchar(max)=''
,#defaultValue varchar(10)='8'
SET #sqlstring=
'ALTER TABLE TABLENAME ADD New_Col8 INT NOT NULL
CONSTRAINT CONSTRAINT_8 DEFAULT (' + (SELECT TOP 1 CAST(number as varchar(2)) FROM
master..spt_values WHERE number=#defaultValue) + ')'
PRINT #sqlstring
EXEC (#sqlstring)

Delete N oldest entries in table

How to delete N oldest entries. I'm limited Sybase. I need to write a stored procedure which would accept a number X and then leave only X newest entries in the table.
For example:
Say ID is auto incremented. The smaller it is, the older this entry is.
ID Text
=========
1 ASD
2 DSA
3 HJK
4 OIU
I need a procedure which would be executed like this.
execute CleanUp 2
and the result will be
ID Text
=========
3 HJK
4 OIU
Note: SQL Server syntax, but should work
Delete from TableName where ID in
(select top N ID from TableName order by ID )
If you want N to be a parameter you will have to construct the statement string and execute it
declare #query varchar(4000)
set #query = 'Delete from TableName where ID in '
set #query = #query + '(select top ' + #N + ' ID from TableName order by ID )'
exec sp_executesql #query
I Like Eduardo's option best as it's the simplest solution, but since Sergej mentions it is quite slow, here's an alternative solution:
Create a stored procedure that does the following:
Create a temp table with the same structure as the original table.
Insert the top N rows into the temp table.
Truncate the original table.
Copy the rows from the temp table back to the original table.
Generally this will be much faster, especially if you have lots of rows in the table.
If you have a clustered index on id, it's safe to execute a delete top query.
delete top 2 from TableName;
I know this is an old question but this can be done without constructing the statement as the top answer say, using a CTE :
WITH MyCTE AS
(
SELECT Field1, Field2, ROW_NUMBER() OVER (ORDER BY Field1 ASC) AS RowNum
FROM MyTable
WHERE Field2 = #WhatIWant
)
DELETE FROM MyCTE WHERE RowNum <= #NbRowsToDelete;