Create duplicates with sql - sql

This might sound a bit confusing at first. But I have a table with data and I want to create duplicates of all the rows in this table. So, if i do:
SELECT *
FROM the_table
it lists all the data in this table. Now, i want to create a copy of all returned results, except for that I want to change data for one column (the date). This will make the new rows unique.
The reason I want to do this is because I want more data in this table since im building statistics out of it for testing purposes. So, if I have this:
**Column1 Column2 Column3**
abc aaa bbb
abcd aaaa bbbb
abcde aaaaa bbbbb
The table will now contain:
**Column1 Column2 Column3**
abc aaa bbb
abcd aaaa bbbb
abcde aaaaa bbbbb
abc aaa bbb_new
abcd aaaa bbbb_new
abcde aaaaa bbbbb_new

insert into your_table
select col1, col2, concat(col3, '_new') from your_table

Consider making a Cartesian Join on your table. This will give you way more data quickly :)

INSERT INTO TABLEDUPLICATES
SELECT * FROM the_table
SELECT * FROM TABLEDUPLICATES UNION
SELECT * FROM the_table

Assuming there is an identity column (ID) you might generate dates (A_Date) like this:
insert into the_table (Column1, Column2, A_Date)
select Column1, Column2, A_Date + (rand(ID) - 0.5) * 100
from the_table

To duplicate rows (all columns) you simply could use
insert into tblname
select * from tblname
to change one column that can be modified to
insert into tblname
select column1, column2, 'fixedvalueforcolumn3' from tblname
But you need a unique value for column 3, so you have to change 'fixedvalueforcolumn3' to a function that will generate some random (unique) value (date in your case) for column 3
insert into tblname
select column1, column2, generateRandomValue() from tblname
Hope that will help you

Related

sql distinct duplicates cross values

I am trying to tidy up a database removing duplicates.
Let's say I have a database that looks like this one
Date | Value1 | Value2
01/01/2018 A B
01/01/2018 B A
02/01/2018 A B
In this case, according to my needs, the first two rows are identical, so I would like to drop one (let's say the second one). If I use SELECT DISTINCT it won't drop it because they are, in fact, different.
Is there an easy procedure to do so?
Thank you
You could use the exists operator to find (and delete!) them:
DELETE FROM mytable a
WHERE EXISTS (SELECT *
FROM mytable b
WHERE a.value1 = b.value2 AND
a.value2 = b.value1 AND
a.value1 < b.value1)
Here's one possibility:
create table t(date,value1,value2);
insert into t values
('01/01/2018','A','B'),
('01/01/2018','B','A'),
('02/01/2018','A','B');
select distinct date,min(value1,value2) value1,max(value1,value2) value2 from t;

ORACLE insertion from other table using TOAD does not align properly (Showing NULL)

I have created new table name NEW_TABLE like
Create table NEW_TABLE
(
Col_1 VARCHAR(50),
Col_2_ VARCHAR(50),
Col_3_ VARCHAR(50)
)
I am inserting value from OLD_TABLE like this way
INSERT INTO NEW_TABLE (Col_1)
SELECT Col_1
FROM OLD_TABLE_A
WHERE Col_1 IS NOT NULL;
INSERT INTO NEW_TABLE (Col_2)
SELECT Col_1
FROM OLD_TABLE_B
WHERE Col_1 IS NOT NULL;
When I want to see the NEW_TABLE it show the data like this
Col_1 Col_2
----- -----
AA
BB
CC
XX
MM
ZZ
PP
CC
I am getting NULL value at the start of Col_2.
I want this:
Col_1 Col_2
----- -----
AA XX
BB MM
CC ZZ
PP
CC
I have to insert different column in different time separately.while inserting a column I do not want to consider other
insert creates new row. If you want to fill column2 values where column1 is already filled you need to use update or merge. But as mentioned in comments you need to know how to match column2 with column1. You haven't provided any join condition for the data so people are guessing what you need. Please post some sample data from tableA and tableB and how it should look in new_table.
I think you need something like:
step1:
INSERT INTO NEW_TABLE (Col_1)
SELECT Col_1
FROM OLD_TABLE_A
WHERE Col_1 IS NOT NULL;
step2:
merge into NEW_TABLE n
using OLD_TABLE_B b
on (/*HERE PUT JOIN CONDITION*/)
when matched then update set n.col_2_ = b.col_1;
step3:
merge into NEW_TABLE n
using OLD_TABLE_C c
on (/*HERE PUT JOIN CONDITION*/)
when matched then update set n.col_3_ = c.col_1;
Since you stated in a comment that there is no relation between the columns, and that there are the same number of columns in old_table_a and old_table_b this will work. I broke it into steps to make following it easier.
First establish the original table with a WITH clause. Then with another WITH clause, add an ID column which is the row number. Finally SELECT, joining on the ID (uncomment the INSERT line at the top when you are satisfied with the results).
Note the "ID" is meaningless as a true ID and serves only to match rows one for one in each table. If these tables have different numbers of rows you will get unexpected results but it meets your requirements.
SQL> --insert into new_table(col_1, col_2)
SQL> -- Set up the original old table A
SQL> with old_table_a(col_1) as (
select 'AA' from dual union
select 'BB' from dual union
select 'CC' from dual
),
-- Add the id, which is the row_number
ota_rn(id, col_1) as (
select row_number() over (order by col_1) as id, col_1
from old_table_a
),
-- Set up the original old table B
old_table_b(col_1) as (
select 'XX' from dual union
select 'YY' from dual union
select 'ZZ' from dual
),
-- Add the id, which is the row_number
otb_rn(id, col_1) as (
select row_number() over (order by col_1) as id, col_1
from old_table_b
)
-- Now join on the ID (which is really meaningless)
select a.col_1, b.col_1
from ota_rn a
join otb_rn b
on (a.id = b.id);
COL_1 COL_1
---------- ----------
AA XX
BB YY
CC ZZ
SQL>
Update before I even post the answer: I see from subsequent comments as I was about to post that you want to allow for adding additional columns with perhaps differing numbers of rows, etc. That will call for UPDATING, not INSERTING and unless you use the fake row_number ID method I use above really makes no sense in a true relational table. In that case this answer will not meet your needs but I will leave it here in case you want to adapt it for your needs.
I suggest you reconsider your approach to your original problem as this path will take you down a dark hole. You will have unrelated attributes in a table which violates basic database design and makes selecting this data in the future problematic at best (how will you query results? I'm curious how you will use this table). Maybe you should take a step back and reconsider your approach and at least start with some properly normalized tables. What's the real issue your are trying to solve? I bet there is a better way.
The second INSERT should be UPDATE, something like:
UPDATE NEW_TABLE
SET Col_2 = (SELECT Col_2
FROM OLD_TABLE
WHERE Col_1 = <selection value>
)
WHERE Col_1 = <selection value> ;
The basic answer is that you should
insert into NEW_TABLE (Col_1, Col_2)
select OLD_TABLE_A.Col_1, OLD_TABLE_B.Col_2
from OLD_TABLE_A, OLD_TABLE_B
where OLD_TABLE_A.Col_1 is not null
and OLD_TABLE_B.Col_2 is not null;
the problem is that you will then get
Col_1 Col_2
----- -----
AA XX
AA YY
AA ZZ
BB XX
BB YY
BB ZZ
CC XX
CC YY
CC ZZ
now the question you need to answer (that's what Dimitry asked in his comment) is how do you decide that you do not want the AA,YY, AA,ZZ, BB,XX, BB,ZZ, CC,XX and CC,YY ? Once you have an answer to this you can augment the where condition to remove them.
select min (case tab when 'A' then Col_1 end) as Col_1
,min (case tab when 'B' then Col_1 end) as Col_2
from ( SELECT 'A' as tab ,rownum as rn ,Col_1 FROM OLD_TABLE_A
union all SELECT 'B' ,rownum ,Col_1 FROM OLD_TABLE_B
)
group by rn
order by rn
;
OR
select min (Col_1) as Col_1
,min (Col_2) as Col_2
from ( SELECT 'A' as tab,rownum as rn,Col_1 ,null as Col_2 FROM OLD_TABLE_A
union all SELECT 'B' ,rownum ,null ,Col_1 FROM OLD_TABLE_B
)
group by rn
order by rn
;
OR
select a.Col_1
,b.Col_1 as Col_2
from (SELECT rownum as rn,Col_1 FROM OLD_TABLE_A) a
full join (SELECT rownum as rn,Col_1 FROM OLD_TABLE_B) b
on b.rn = a.rn
order by coalesce (a.rn,b.rn)
;
Results
+-------+-------+
| COL_1 | COL_2 |
+-------+-------+
| AA | XX |
+-------+-------+
| BB | MM |
+-------+-------+
| CC | ZZ |
+-------+-------+
| | PP |
+-------+-------+
| | CC |
+-------+-------+
The problem as I see it is:
Fill any holes in Col_2 with one of each of the values from
OLD_TABLE_B, when you've run out of holes then add new rows.
Exactly the same technique should to fill Col_3 from OLD_TABLE_C, as so on. Ideally the initial Col_1 from OLD_TABLE_A should also be able to use the technique although it's a simple insert.
If you end up with an OLD_TABLE_B_PART_2 this should be able to be run against Col_2 later with the same technique.
The solution needs the following parts:
A MERGE statement as you need to do updates otherwise inserts.
To use a single MERGE for each pass to update multiple rows, each row with different values, you need a unique way of identifying the row for the ON clause. With no unique column(s) / primary key you need to use the ROWID pseudo-column. This will be very efficient at targeting the row in the table when we get to the UPDATE clause as ROWID encodes the physical location of the row.
You need all the rows from OLD_TABLE and as many matching rows from NEW_TABLE you can find with holes, so it's a LEFT OUTER JOIN. You could do some sort of UNION then aggregate the rows but this would need an often expensive GROUP BY and you many need to discard an unknown number of surplus rows from NEW_TABLE.
To match a (potentially non-unique) row in the OLD_TABLE with a unique hole in the NEW_TABLE, both will need a temporary matching IDs. The ROWNUM pseudo-column does this and is cheap.
Given the above, the following statement should work:
MERGE INTO NEW_TABLE
USING
( SELECT Col_1, ntid
FROM
( SELECT ROWNUM num, Col_1
FROM OLD_TABLE_B
WHERE Col_1 IS NOT NULL
) ot
LEFT OUTER JOIN
( SELECT ROWNUM num, ROWID ntid
FROM NEW_TABLE
WHERE Col_2 IS NULL
) nt ON nt.num=ot.num
) sel
ON (NEW_TABLE.ROWID=ntid)
WHEN MATCHED THEN
UPDATE SET Col_2=sel.Col_1
WHEN NOT MATCHED THEN
INSERT (Col_2) VALUES (sel.Col_1);
Check the execution plan before using on big data tables. I've seen the optimiser (in Oracle 12c) use a MERGE or HASH join against the target (NEW_TABLE) for the update rather than a plain USER-ROWID access. In this case the workaround I have used was to force NESTED-LOOP joins i.e. add an optimisation hint to the MERGE at the start of the query, so MERGE /*+ use_nl(NEW_TABLE) */. You may also need to check how it does LEFT JOIN depending on your data.
Create table NEW_TABLE
(
Col_1 VARCHAR(5),
Col_2_ VARCHAR(5),
Col_3_ VARCHAR(5)
);
Create table OLD_TABLE
(
Col_1 VARCHAR(5),
Col_2_ VARCHAR(5),
Col_3_ VARCHAR(5)
);
insert into old_table values ('AA','XX', null);
insert into old_table values ('BB','MM', null);
insert into old_table values ('CC','ZZ', null);
insert into old_table values (null,'PP', 'YYY');
insert into old_table values (null,'CC', 'XXX');
select * from old_table;
COL_1 COL_2 COL_3
----- ----- -----
AA XX
BB MM
CC ZZ
PP YYY
CC XXX
alter table new_table add (position number);
.
MERGE INTO new_table D
USING (select rownum position, old_table.* from old_table where col_1 is not null) S
ON (d.position = s.position)
WHEN MATCHED THEN UPDATE SET D.Col_1 = S.Col_1
WHEN NOT MATCHED THEN INSERT (d.position, D.Col_1)
VALUES (s.position, S.Col_1);
MERGE INTO new_table D
USING (select rownum position, old_table.* from old_table where col_2_ is not null) S
ON (d.position = s.position)
WHEN MATCHED THEN UPDATE SET D.Col_2_ = S.Col_2_
WHEN NOT MATCHED THEN INSERT (d.position, D.Col_2_)
VALUES (s.position,S.Col_2_);
MERGE INTO new_table D
USING (select rownum position, old_table.* from old_table where col_3_ is not null) S
ON (d.position = s.position)
WHEN MATCHED THEN UPDATE SET D.Col_3_ = S.Col_3_
WHEN NOT MATCHED THEN INSERT (d.position, D.Col_3_)
VALUES (s.position, S.Col_3_);
select * from new_table order by position;
COL_1 COL_2 COL_3 POSITION
----- ----- ----- ----------
AA XX YYY 1
BB MM XXX 2
CC ZZ 3
PP 4
CC 5
You can drop POSITION column from new_table after the operation if you wish.
run below query
INSERT INTO NEW_TABLE (Col_1, Col_2)
( SELECT Col_1, Col_2
FROM OLD_TABLE_A
WHERE not (Col_1 IS NULL and Col_2 IS NULL))
You can't do that like your way.
TRY THIS
INSERT INTO NEW_TABLE (Col_1,COL_2)
SELECT A.Col_1,B.COL_1
FROM OLD_TABLE_A A FULL OUTER JOIN OLD_TABLE_B B ON 1=1
AND A.Col_1 IS NOT NULL
AND B.Col_1 IS NOT NULL;

How to get unique value from sql table based on charachter length of value

Here I have two columns like below example column1 & column2 in sql table and i want to get unique value row on the basis of column2 column value from table
Below example of dummy table
Column1 Column2
---------- -------------
1001 ab
1001 abc
1001 abcd
2001 wxyz
2001 wxy
2001 wx
In above example value starting from a & another value starting from w in Column2
On the basis of same value character length, i want to get result like below
Output:
Column1 Column2
---------- -----------
1001 abcd
2001 wxyz
Thanks in advance of help :)
If I understood you correctly, you want the highest length (you didn't say what to do when there are two with the same length) but basically you want something like this:
SELECT * FROM YourTable
WHERE (column1,len(column2)) IN(select Column1,max(len(column2))
FROM YourTable
GROUP BY Column1)
If you are looking if your values in column2 are somewhere included in other rows, in other words: If you are looking for rows with combinations of characters which are unique on their own, this might be your solution:
CREATE TABLE TestTable(Column1 INT,Column2 VARCHAR(100));
INSERT INTO TestTable VALUES
(1001,'ab')
,(1001,'abc')
,(1001,'abcd')
,(2001,'wxyz')
,(2001,'xyz')
,(2001,'yz');
SELECT *
FROM TestTable
WHERE NOT EXISTS(SELECT 1
FROM TestTable AS x
WHERE x.Column1=TestTable.Column1
AND LEN(x.Column2)>LEN(TestTable.Column2)
AND x.Column2 LIKE '%' + TestTable.Column2 + '%'
)
DROP TABLE TestTable;

Decomposing a GROUP BY statement

Assuming I have a table SomeTable with the following data:
Primary Key Column1 Column2 Column3 Column4 Column5 Num
1 dat1 abc1 dat3 dat4 por7 1
2 dat1 gcd4 dat3 dat4 yrt8 6
3 dat1 iut7 dat3 dat4 asd6 2
4 other1 other2 other3 other4 other5 4
Another table SomeTableGrouped with a "Group Byed" version created using a query like this:
INSERT INTO SomeTableGrouped
SELECT Column1, Column3, Column4, SUM(Num)
FROM SomeTable
GROUP BY Column1, Column3, Column4
Primary Key Column1 Column3 Column4 Num
100 dat1 dat3 dat4 9
200 other1 other3 other4 4
What I'd like to be able to do is, if I have a primary key of SomeTableGrouped, I need to be able to tell which specific rows from SomeTable it came from.
Example:
In a separate table RandomTable, I have data like this:
Primary Key Column1 SomeTableGroupedId
1 dat1 100
2 dat2 100
If I look at the first row, I need to be able to list out row 1 - 3 from SomeTable
How can I do this? I can't change the schema very much (ie. I can only add new columns, remove columns, add a new table) so a dirty solution is perfectly fine with me.
I think this is what you want.
SELECT id
FROM SomeTable
INNER JOIN SomeTableGrouped ON
(SomeTable.Column1 = SomeTableGrouped.Column1) AND
(SomeTable.Column2 = SomeTableGrouped.Column2) AND
(SomeTable.Column3 = SomeTableGrouped.Column3)
WHERE SomeTableGrouped.id = ...
You don't even need to create all those tables, you only need SomeTable. But here we go...
If you want to find the IDs of the records that summed up, just relate them as they were created:
select st.PrimaryKey as STPK, stg.PrimaryKey as STGPK
from SomeTable st
inner join SomeTableGrouped stg
on (st.Column1 = stg.Column1 and
st.Column3 = stg.Column3 and
st.Column5 = stg.Column5)
However, you should not even have created SomeTableGroupedas a table. It could be a view (look here to see how create views in DB2).
That way, you make sure data is always up-to-date and you don't have to worry about back tracking ("what if Num gets updated?").

Is it possible to use WHERE IN along with LIKE?

If I have to search for some data I can use wildcards and use a simple query -
SELECT * FROM TABLE WHERE COL1 LIKE '%test_string%'
And, if I have to look through many values I can use -
SELECT * FROM TABLE WHERE COL1 IN (Select col from AnotherTable)
But, is it possible to use both together. That is, the query doesn't just perform a WHERE IN but also perform something similar to WHERE LIKE? A query that just doesn't look through a set of values but search using wildcards through a set of values.
If this isn't clear I can give an example. Let me know. Thanks.
Example -
lets consider -
AnotherTable -
id | Col
------|------
1 | one
2 | two
3 | three
Table -
Col | Col1
------|------
aa | one
bb | two
cc | three
dd | four
ee | one_two
bb | three_two
Now, if I can use
SELECT * FROM TABLE WHERE COL1 IN (Select col from AnotherTable)
This gives me -
Col | Col1
------|------
aa | one
bb | two
cc | three
But what if I need -
Col | Col1
------|------
aa | one
bb | two
cc | three
ee | one_two
bb | three_two
I guess this should help you understand what I mean by using WHERE IN and LIKE together
SELECT *
FROM TABLE A
INNER JOIN AnotherTable B on
A.COL1 = B.col
WHERE COL1 LIKE '%test_string%'
Based on the example code provided, give this a try. The final select statement presents the data as you have requested.
create table #AnotherTable
(
ID int IDENTITY(1,1) not null primary key,
Col varchar(100)
);
INSERT INTO #AnotherTable(col) values('one')
INSERT INTO #AnotherTable(col) values('two')
INSERT INTO #AnotherTable(col) values('three')
create table #Table
(
Col varchar(100),
Col1 varchar(100)
);
INSERT INTO #Table(Col,Col1) values('aa','one')
INSERT INTO #Table(Col,Col1) values('bb','two')
INSERT INTO #Table(Col,Col1) values('cc','three')
INSERT INTO #Table(Col,Col1) values('dd','four')
INSERT INTO #Table(Col,Col1) values('ee','one_two')
INSERT INTO #Table(Col,Col1) values('ff','three_two')
SELECT * FROM #AnotherTable
SELECT * FROM #Table
SELECT * FROM #Table WHERE COL1 IN(Select col from #AnotherTable)
SELECT distinct A.*
FROM #Table A
INNER JOIN #AnotherTable B on
A.col1 LIKE '%'+B.Col+'%'
DROP TABLE #Table
DROP TABLE #AnotherTable
Yes. Use the keyword AND:
SELECT * FROM TABLE WHERE COL1 IN (Select col from AnotherTable) AND COL1 LIKE '%test_string%'
But in this case, you are probably better off using JOIN syntax:
SELECT TABLE.* FROM TABLE JOIN AnotherTable on TABLE.COL1 = AnotherTable.col WHERE TABLE.COL1 LIKE '%test_string'
no because each element in the LIKE clause needs the wildcard and there's not a way to do that with the IN clause
The pattern matching operators are:
IN, against a list of values,
LIKE, against a pattern,
REGEXP/RLIKE against a regular expression (which includes both wildcards and alternatives, and is thus closest to "using wildcards through a set of valuws", e.g. (ab)+a|(ba)+b will match all strings aba...ba or bab...ab),
FIND_IN_SET to get the index of a string in a set (which is represented as a comma separated string),
SOUNDS LIKE to compare strings based on how they're pronounced and
MATCH ... AGAINST for full-text matching.
That's about it for string matching, though there are other string functions.
For the example, you could try joining on Table.Col1 LIKE CONCAT(AnotherTable.Col, '%'), though performance will probably be dreadful (assuming it works).
Try a cross join, so that you can compare every row in AnotherTable to every row in Table:
SELECT DISTINCT t.Col, t.Col1
FROM AnotherTable at
CROSS JOIN Table t
WHERE t.col1 LIKE ('%' + at.col + '%')
To make it safe, you'll need to escape wildcards in at.col. Try this answer for that.
If I understand the question correctly you want the rows from "Table" when "Table.Col1" is IN "AnotherTable.Col" and you also want the rows when Col1 IS LIKE '%some_string%'.
If so you want something like:
SELECT
t.*
FROM
[Table] t
LEFT JOIN
[AnotherTable] at ON t.Col1 = at.Col
WHERE (at.Col IS NOT NULL
OR t.Col1 LIKE '%some_string%')
Something like this?
SELECT * FROM TABLE
WHERE
COL1 IN (Select col from AnotherTable)
AND COL1 LIKE '%test_string%'
Are you thinking about something like EXISTS?
SELECT * FROM TABLE t WHERE EXISTS (Select col from AnotherTable t2 where t2.col = t.col like '%test_string%' )