I would like to update my table and replace string CarHer into MobileAuto in varchar field but only the if it's at the starting position in entire value stirng. For instance i got this input:
CarHer machine sixt CarHer emerte67 34
CarHer
CarHer right 22CarHer
CarHer 222 ass
So at the end i would like to achieve this:
MobileAuto machine sixt CarHer emerte67 34
MobileAuto
MobileAuto right 22CarHer
MobileAuto 222 ass
How can i do this in very safety way?
One option is STUFF()
Example
Declare #YourTable Table ([SomeCol] varchar(50)) Insert Into #YourTable Values
('CarHer machine sixt CarHer emerte67 34')
,('CarHer')
,('CarHer right 22CarHer')
,('CarHer 222 ass')
Update #YourTable
Set SomeCol = stuff(SomeCol,1,6,'MobileAuto')
Where SomeCol like 'CarHer%'
Select * From #YourTable
Updated Table
SomeCol
MobileAuto machine sixt CarHer emerte67 34
MobileAuto
MobileAuto right 22CarHer
MobileAuto 222 ass
EDIT: As a Select
SELECT SomeCol
, NewVal = stuff(SomeCol,1,6,'MobileAuto')
From YourTable
Where SomeCol like 'CarHer%'
Related
Our system is a SAAS based system we use ClientID as a Masking for data fetching.
The DB load is based on the Size of the Company. So we partitioned the DB based on ClientID
Example: Before Partition
clienttable
clientid
clientname
clientaddress
1
ABC
...
2
EMN
...
3
XYZ
...
employeetable
clientid
employeeid
employeename
1
123
AAA
1
124
BBB
2
125
CCC
2
126
DDD
3
127
EEEE
jobtable
clientid
jobid
jobname
1
234
YTR
1
235
DER
2
236
SWE
3
237
VFT
3
238
GHJ
Example: After Partition
clienttable
clientid
clientname
clientaddress
1
ABC
...
2
EMN
...
3
XYZ
...
employeetable
employeetable_1
clientid
employeeid
employeename
1
123
AAA
1
124
BBB
employeetable_2
clientid
employeeid
employeename
2
125
CCC
2
126
DDD
employeetable_3
clientid
employeeid
employeename
3
127
EEE
jobtable
jobtable_1
clientid
jobid
jobname
1
234
YTR
1
235
DER
jobtable_2
clientid
jobid
jobname
2
236
SWE
jobtable_3
clientid
jobid
jobname
3
237
VFT
3
238
GHJ
When we write select queries:
Select employeeid,employeename from employeetable where clientid=2;
This query runs faster after partition. The problem we face is we have some user defined function to manipulate some data.
CREATE OR REPLACE FUNCTION GET_JOB_COUNT(NUMERIC, NUMERIC) RETURNS NUMERIC AS $BODY$
DECLARE
p_client_id ALIAS FOR $1;
p_employee_id ALIAS FOR $2;
v_is_count NUMERIC := 0;
BEGIN
SELECT COUNT(JOB_ID) INTO v_is_count FROM JOBTABLE where CLIENTID=p_client_id AND CREATEDBY=p_employee_id;
RETURN v_is_count;
END; $BODY$
LANGUAGE plpgsql;
Select employeeid,employeename,GET_JOB_COUNT(2,employeeid) from employeetable where clientid=2;
This query is slow after partition. Does this means the GET_JOB_COUNT function is run across Partition?
Is that the problem, then we can't use Functions like this in Select query after partition?
The function will be called once for each and every row from the employeetable (that is selected through the WHERE clause). I doubt you can improve the performance in any significant way using that approach.
It's better to do the aggregation (=count) for all rows at once, rather than for each row separately:
select e.employeeid, employeename, t.cnt
from employeetable e
left join (
select clientid, createdby, count(job_id) as cnt
from jobtable
group by client_id, created_by
) j on j.clientid = e.clientid and j.createdby = e.employeeid
where e.clientid = 2;
Another option to try is to use a lateral join to eliminate rows from the jobtable early - I am not sure if the optimizer is smart enough for that in the query above. So you can try this as an alternative:
select e.employeeid, employeename, j.cnt
from employeetable e
left join lateral (
select count(jt.job_id) as cnt
from jobtable jt
where jt.clientid = e.clientid
and jtcreatedby = e.employeeid
) j on true
where e.clientid = 2;
If you really do want to stick with the function, maybe making it a SQL function helps the optimizer. It at least removes the overhead of calling PL/pgSQL code:
CREATE OR REPLACE FUNCTION get_job_count(p_client_id numeric, p_employee_id numeric)
returns bigint
as
$body$
SELECT COUNT(JOB_ID)
FROM JOBTABLE
where CLIENTID = p_client_id
AND CREATEDBY = p_employee_id;
$BODY$
LANGUAGE sql
stable
parallel safe;
But I doubt that you will see a substantial improve by that.
As a side not: using numeric for an "ID" column seems like a rather strange choice. Why aren't you using int or bigint for that?
How to change "65→67→69" to "J7,G2,P9" in SQL/PostgreSQL/MySQL? Or use split fields/value mapper in Pentaho Data Integration (Spoon) to realize it?
I use KETTLE(Pentaho Data Integration/Spoon) to insert data to PostgreSQL from other databases, I have a field with below data
value
-----------
65→67→69
15→19→17
25→23→45
19→28→98
ID value
--------
65 J7
67 G2
69 P9
15 A8
19 b9
17 C1
25 b12
23 e12
45 A23
28 C17
98 F18
And how to change the above value to the below value? Is there any SQL way or KETTLE way to realize it?
new_value
-----------
J7,G2,P9
A8,b9,C1
b12,e12,A23
b9,C17,B18
Thanks so much for any advice.
Assuming these tables:
create table table1 (value text);
insert into table1 (value)
values
('65→67→69'),
('15→19→17'),
('25→23→45'),
('19→28→98')
;
create table table2 (id int, value text);
insert into table2 (id, value)
values
(65, 'J7'),
(67, 'G2'),
(69, 'P9'),
(15, 'A8'),
(19, 'b9'),
(17, 'C1'),
(25, 'b12'),
(23, 'e12'),
(45, 'A23'),
(28, 'C17'),
(98, 'F18')
;
In Postgres you can use a scalar subselect:
select t1.value,
(select string_agg(t2.value, ',' order by t.idx)
from table_2 t2
join lateral unnest(string_to_array(t1.value,'→')) with ordinality as t(val,idx) on t2.id::text = t.val
) as new_value
from table_1 t1;
Online example
How do i update inventory_id in TABLE2 from TABLE1 inventory_id?
So far I've tried
UPDATE TABLE2
SET
inventory_id=t1.inventory_id
FROM TABLE2 t2
INNER JOIN
TABLE1 t1
ON t1.test_id = t2.test_id
WHERE t1.test_id = t2.test_id;
But this sets all the value of inventory_id in TABLE2 as 1 instead of my expected result.
TABLE1
inventory_id test_id
1 26
2 56
3 12
4 67
TABLE2
test_id inventory_id
12
26
56
67
Such that it becomes like this?
TABLE2
test_id inventory_id
12 3
26 1
56 2
67 4
The documentation on UPDATE states:
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
...
[ FROM from_item [, ...] ]
(...)
from_item
A table expression allowing columns from other tables to appear in the
WHERE condition and update expressions. This uses the same syntax as
the FROM clause of a SELECT statement; for example, an alias for
the table name can be specified. Do not repeat the target table as a
from_item unless you intend a self-join (in which case it must appear with an alias in the from_item).
(emphasis: me)
So following that you want:
UPDATE table2 t2
SET inventory_id = t1.inventory_id
FROM table1 t1
WHERE t1.test_id = t2.test_id;
db<>fiddle
You pretty much had it but seem to got confused by the syntax you may have seen for other DBMS and mixed them.
Normally the PostgreSQL UPDATE JOIN syntax should give:
UPDATE TABLE2 t2
SET
t2.inventory_id=t1.inventory_id
FROM TABLE1 t1
WHERE t1.test_id = t2.test_id;
This question already has answers here:
Turning a Comma Separated string into individual rows
(16 answers)
Closed 5 years ago.
Suppose I have a table like this with an undetermined number of comma-delimited values in one column:
thingID personID
1 123,234,345
2 456,567
and I want to get it into a form like this:
thingID personID
1 123
1 234
1 345
2 456
2 567
What is my best option for doing this?
Oh I should mention the data is in a SQL 2008 R2 database so I may not be able to use the very latest functionality.
Use CROSS APPLY with a string splitting function.
To find the string splitting function that works best for you, read Aaron Bertrand's Split strings the right way – or the next best way.
For this demonstration I've chosen to use the SplitStrings_XML function, simply because it's the first pure t-sql function in the article:
CREATE FUNCTION dbo.SplitStrings_XML
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
Now that we have a string splitting function, create and populate the sample table (Please save us this step in your future questions):
DECLARE #T AS TABLE
(
thingID int,
personID varchar(max)
)
INSERT INTO #T VALUES
(1, '123,234,345'),
(2, '456,567')
The query:
SELECT thingId, Item
FROM #T
CROSS APPLY dbo.SplitStrings_XML(personID, ',')
Results:
thingId Item
1 123
1 234
1 345
2 456
2 567
You can see a live demo on rextester.
There are several ways to do that. Here are two methods for SQL Server 2008:
XML-Method: requires the string to allow for the xml-trick (no invalid XML chars)
SELECT a.thingID, Split.a.value('.', 'VARCHAR(100)') AS Data
FROM (SELECT OtherID,
CAST('<M>' + REPLACE(personID, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM table1) AS A CROSS APPLY Data.nodes ('/M') AS Split(a);
Recursive method:
;WITH tmp(thingID, DataItem, Data) AS (
SELECT thingID, LEFT(personID, CHARINDEX(',', personID + ',') - 1),
STUFF(personID, 1, CHARINDEX(',', personID + ','), '')
FROM table1
UNION ALL
SELECT thingID, LEFT(personID, CHARINDEX(',', personID + ',') - 1),
STUFF(personID, 1, CHARINDEX(',', personID + ','), '')
FROM tmp
WHERE Data > ''
)
SELECT thingID, DataItem AS personID
FROM tmp
Sorry for the late response I was off for few days, and for not specifying the exact table structure. Please ignore the previous description above. I have more information so my original question is not any longer valid as I obtain more information regarding what I really need as described below:
I have the following table (simplified version for the sake of discussion). First line is the headers:
VariableID DocumentID Revision Value
44 12 2 Val1
45 12 2 Val2
45 12 3 Val3
44 13 1 Val4
46 13 2 Val5
47 14 1 Val6
I’d like to convert it (assuming n number of rows) to the following grouped by (DocumentId, revision) table:
Documentid revision variable1 (44) variable2 (45) variable3(46) variable(47) variable (n)
12 2 Val1 Val2 null null
12 3 null Val3 null null
13 1 Val4 null null null
13 2 null null Val5 null
14 1 null null null Val6
Number of variable will be retrieved dynamically. I do not know how many variable will be in source table as input.
Please advise.
You did not provide a lot of details about your current table structure or sample data. So I will provide you with some samples of the PIVOT function that will perform this.
There are two options for PIVOT, a Static if you know the number of columns to transform or a Dynamic which will get the list of columns at run-time to transform.
EDIT:
Based on the change to your question, you can still perform a PIVOT
A Static Pivot would look like this (Sql Fiddle sample):
select *
from
(
select *
from t
) x
pivot
(
max(value)
for variableid in([44], [45], [46], [47])
) p
As Dynamic Pivot looks like this (Sql Fiddle Sample):
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsAlias AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(variableid)
from t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #colsAlias = STUFF((SELECT DISTINCT ',' + QUOTENAME(m.variableid) + ' AS ' + QUOTENAME('variable' + cast(n.variableid as varchar(10)))
FROM t m INNER JOIN t n ON m.variableid = n.variableid
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT documentid, revision, ' + #colsAlias + ' from
(
select *
from t
) x
pivot
(
max(value)
for variableid in (' + #cols + ')
) p '
execute(#query)
The PIVOT operator sounds like it is what you are looking for, it is available in both Microsoft SQL Server and Microsoft Access, I'm not sure if it is available in Sybase though. Here is the MSDN article on it: T-SQL Pivot Operator