sql update query - sql

I want to strip off all _ prefixes in the name column, but the result may cause a conflict. So if the result duplicates with existing ones, I want to suffix a _ to it until there's no duplication.
In the below example case, _test should be renamed to test___.
create table A
(
name VARCHAR2(20) unique,
id int
);
insert into a (name, id) values ('_test', 1);
insert into a (name, id) values ('test', 2);
insert into a (name, id) values ('test_', 3);
insert into a (name, id) values ('test__', 4);

Try this:
merge into A
using (with aa as (select id, trim('_' from name) name from A)
select rpad(name,
length(name) - 1 + row_number()
over(partition by name order by id),
'_') name2,
id
from AA) s
on (s.id = a.id)
when matched then
update set a.name = s.name2

Related

Copy Sql Server Graph database with data

I am having a simple SQL Graph Database.
Database:
CREATE TABLE Person (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE City (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE Travels AS EDGE;
INSERT INTO Person VALUES (3,'Cecil');
INSERT INTO Person VALUES (4,'Diane');
INSERT INTO Person VALUES (2,'Bob');
INSERT INTO Person VALUES (1,'Alice');
Insert into City VALUES (1, 'Almaty')
Insert into City VALUES (2, 'Bangkok')
Insert into City VALUES (3, 'Casablanca')
Insert into City VALUES (4, 'Dublin')
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 1),
(SELECT $node_id FROM City WHERE ID = 1));
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 2),
(SELECT $node_id FROM City WHERE ID = 2));
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 3),
(SELECT $node_id FROM City WHERE ID = 3));
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 4),
(SELECT $node_id FROM City WHERE ID = 4));
I would like to copy these tables to a different tables. My goal is to make it within C#, but simple TSQL solution would be good enough.
CREATE TABLE Person2 (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE City2 (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE Travels2 AS EDGE;
I can copy data from Node tables easily, if i would read only user data and not an internal column $node_id:
insert into Person2(ID, name) (select Id, name from Person)
insert into City2(ID, name) (select id, name from City)
but in table Travels, I am having just this information:
select $edge_id, $from_id, $to_id from Travels :
{"type":"edge","schema":"dbo","table":"Travels","id":0} {"type":"node","schema":"dbo","table":"Person","id":3} {"type":"node","schema":"dbo","table":"City","id":0}
and in order to copy this, i would need to create a join over tables Person, City, Travels to get original IDS and then join it with Person2 and City2 to get new values $from_id, $to_id for Travels2
Another option would be to use functions Graph_ID_FROM_NODE_ID and NODE_ID_FROM_PARTS:
insert into Person2($node_id, ID, name)
(select ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.Person2'),Graph_ID_FROM_NODE_ID($node_id)), Id, name from Person )
insert into City2($node_id, ID, name)
(select ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.City2'),Graph_ID_FROM_NODE_ID($node_id)), Id, name from City )
Insert into Travels2 ($edge_id, $from_id, $to_id)
(select ''+EDGE_ID_FROM_PARTS(OBJECT_ID('dbo.Travels2'), Graph_ID_FROM_EDGE_ID($edge_id)), ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.Person2'),Graph_ID_FROM_NODE_ID($from_id)), ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.City2'),Graph_ID_FROM_NODE_ID($to_id)) from Travels
)
Probably, i don't need to copy ids of edges, so last insert would be a bit easier, but i wonder, if there is not any easier way how to copy graph tables.

Increment an ID within an INSERT INTO statement in AS400

Is there a way to insert a new record to a table that has an non-unique id and set this id to the next number in the same SQL statement?
Something like
INSERT INTO T1 (id, fname, lname)
VALUES ([last id + 1], 'Dan', 'Thomson');
this probably works
INSERT INTO T1 (id, fname, lname)
VALUES (ifnull((select max(id) from T1),0) + 1, 'Dan', 'Thomson')
DECLARE #COUNTER INT;
SET #COUNTER = 1;
WHILE(#COUNTER <= XXX)
BEGIN
INSERT INTO T1 (id, fname, lname)
VALUES (#COUNTER, #FNAME , #LNAME);
SET #COUNTER = #COUNTER + 1;
END
Built-in function MAX :
INSERT INTO T1 (id, fname, lname)
SELECT ifnull(MAX(id)+ 1,1), 'Dan', 'Thomson' FROM T1
Insert and set value with max()+1 problems
SELECT MAX(col) +1 is not safe -- it does not ensure that you aren't inserting more than one customer with the same customer_id value, regardless if selecting from the same table or any others.
For performance, add an index:
CREATE INDEX T1_INDEX1 ON T1 (id) DESC
References:
MAX()
CREATE INDEX
Index Advisor, Show Statements
Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology
Unit Test
-- Create Table
SET SCHEMA QTEMP;
CREAT TABLE testtbl (
id integer not null default,
fname char(10) not null default,
lname char(10) not null default)
;
-- Initialize Table with Data
insert into
testtbl ( id , fname, lname)
values
( 1, 'fname1', 'lname_1'),
( 2, 'fname2', 'lname_2'),
( 2, 'fname3', 'lname_3'),
( 3, 'fname4', 'lname_4')
;
-- Test Insert Statement
INSERT INTO
testtbl ( id, fname, lname )
SELECT ifnull(MAX( id ) + 1, 1), 'Dan', 'Thomson' FROM testtbl;
--Confirm Expectation
select * from testtbl;
ID FNAME LNAME
-------------------------------------
1 fname1 lname_1
2 fname2 lname_2
3 fname4 lname_4
4 Dan Thomson
if you want insert all content of table with unique id start with max +1
INSERT INTO T1 (id, fname, lname)
select
rownumber() over() + ifnull((select max(T1.id) from T1), 0),
T2.zone1, T2.zone2
from T2

Sql insert multiple rows if not exists

I have a sql table that has two columns id and name. I have list of names about 20 and I need to write a query that checks if name exists before insert.
Is there a better way of doing this rather then just having the below query 20 times but with different names (I need do this in t-sql):
IF NOT EXISTS(SELECT*
FROM mytable
WHERE name = 'Dan')
BEGIN
INSERT INTO mytable
(name)
VALUES ('dan')
END
INSERT INTO MyTable (Name)
SELECT NewNames.Name
FROM ( VALUES ('Name1'), ('Name2'), ('Name3') ) AS NewNames (Name)
WHERE NOT EXISTS ( SELECT 1
FROM MyTable AS MT
WHERE MT.Name = NewNames.Name );
I think you could use a merge statement:
MERGE INTO myTable AS Target
USING (VALUES ('name1'),('name2'),('...')) AS source (NAME)
ON Target.NAME = Source.NAME
WHEN NOT MATCHED BY TARGET THEN
INSERT (NAME) VALUES (name)
You can filter values with NOT EXISTS
INSERT INTO myTable (
Name
)
SELECT DISTINCT
Name
FROM (
VALUES ('Name 1'),
('Name 2')
) AS NewNames(Name)
WHERE
NOT EXISTS (SELECT 1 FROM TargetTable WHERE myTable.Name = NewNames.Name)
If your new names are in another table, you can change the select query in the above one.
Please note, that the DISTINCT keyword is necessary to filter out the duplications in the source data.
I would do this using insert:
with names as (
select 'Dan' as name union all
select 'name2' union all
. . .
)
insert into myTable(name)
select distinct name
from myTable
where not exists (select 1 from mytable t2 where t2.name = t.name);
Note: you may want to create a unique index on mytable(name) so the database does the checking for duplicates.
untested so there might be some minor errors:
merge into mytable x
using (
values ('name1')
, ('name2')
, ...
, ('namen')
) as y (name)
on x.name = y.name
when not matched then
insert (name)
values (y.name)
INSERT INTO MyTable (Name)
SELECT Name FROM
(
VALUES ('Name 1'),
('Name 2')
) AS Names(Name)
WHERE Name NOT IN
(
SELECT Name FROM MyTable
)
INSERT IGNORE INTO myTable (column1, column2) VALUES (val1, val2),(val3,val4),(val5,val6);
INSERT IGNORE will allow skip on duplicate values

Conditions Within An Insert

Is it possible to do something like having an IF statement within an INSERT like so;
INSERT INTO #TABLE (ID, NAME, ADDRESS)
VALUES(
IF CONDITION (SELECT DATA)
ELSE (SELECT DATA)
)
Sort of...
INSERT INTO #TABLE (ID, NAME, ADDRESS)
SELECT
CASE condition WHEN result then id else id2 end,
CASE condition WHEN result then name else name2 end,
...
or with a UNION
INSERT INTO #TABLE (ID, NAME, ADDRESS)
SELECT data FROM source WHERE condition
UNION
SELECT data FROM othersource WHERE NOT(condition)

SQL one-to-many match the one side by ALL in many side

In the following one to many
CREATE TABLE source(id int, name varchar(10), PRIMARY KEY(id));
CREATE TABLE params(id int, source int, value int);
where params.source is a foreign key to source.id
INSERT INTO source values(1, 'yes');
INSERT INTO source values(2, 'no');
INSERT INTO params VALUES(1,1,1);
INSERT INTO params VALUES(2,1,2);
INSERT INTO params VALUES(3,1,3);
INSERT INTO params VALUES(4,2,1);
INSERT INTO params VALUES(5,2,3);
INSERT INTO params VALUES(6,2,4);
If i have a list of param values (say [1,2,3]), how do I find all the sources that have ALL of the values in the list (source 1, "yes") in SQL?
Thanks
SELECT s.*
FROM source AS s
JOIN params AS p ON (p.source = s.id)
WHERE p.value IN (1,2,3)
GROUP BY s.id
HAVING COUNT(DISTINCT p.value) = 3;
You need the DISTINCT because your params.value is not prevented from having duplicates.
Edit Modified to handle case where there can be multiple occurances of the value for a given source.
Try this:
SELECT
*
FROM
source
WHERE
(
SELECT COUNT(DISTINCT value)
FROM params
WHERE params.source = source.id
AND params.value IN (1, 2, 3)
) = 3
You can rewrite it to a GROUP BY as well:
SELECT
source.*
FROM
source
INNER JOIN params ON params.source = source.id
WHERE
params.value IN (1, 2, 3)
GROUP BY
source.id,
source.name
HAVING
COUNT(DISTINCT params.value) = 3