Union columns and remove blanks - sql

I have a table which appears like this (I've shortened it for example purposes)
no no19 no68
3387034694344500
3387452540705400
3388486878919450
3371522572594880
3372232397709690
3373608476884750
3382142940562320
3382142940562320
3383084144363070
so no, no19 and no68 are 3 different columns, but the data in column 'no19' starts in the next row after data in column 'no' ends.
As between these columns I have a lot more data, I would like to create a readable table. I have merged these columns into one, using this code:
CREATE TABLE MULTICURRENCY_CHECK
(
TOKEN varchar(255)
)
INSERT INTO MULTICURRENCY_CHECK
(
TOKEN
)
SELECT no FROM book1
UNION ALL
SELECT no19 FROM book1
UNION ALL
SELECT no68 FROM book1
The problem is, the result I got looks like this:
TOKEN
3387034694344500
3387452540705400
3388486878919450
3371522572594880
3372232397709690
3373608476884750
3382142940562320
3382142940562320
3383084144363070
So there are blank rows between in column TOKEN. I've tried to delete them, but it by simple delete command but it's not working (tried those two below):
delete from multicurrency_check where TOKEN = ' '
delete from multicurrency_check where TOKEN is NULL
Perhaps there is a different way I should deal with this table, maybe quicker? As the original table looks like these (just sample data)
no a b no19 c d no68
3387034694344500 data1 data4
3387452540705400 data2 data5
3388486878919450 data3 data6
3371522572594880 data7 data10
3372232397709690 data8 data11
3373608476884750 data9 data12
3382142940562320
3382142940562320
3383084144363070
so what I would like to have in the end is table like this:
| TOKEN | a | b | c | d
where token is a merge of no, no19 and no68, and then folowwing a,b,c,d columns with data matching appropriate id from TOKEN column (a,b,c,d can be null)

You could delete them in your UNION query like:
SELECT no FROM table WHERE no IS NOT NULL
UNION
SELECT no19 FROM table WHERE no19 IS NOT NULL
UNION
SELECT no68 FROM table where no68 IS NOT NULL
You could also use COALESCE() instead of union since a column only contains data when the other's are null:
SELECT COALESCE(no, no19, no68) FROM table
Instead of putting these values in their own table, you could start with the above queries and build off of them. Say you want to also bring in A,B or C,D into the results:
SELECT COALESCE(no, no19, no68) as newno, COALESCE(a,c) as ac, COALESCE(b,d) as bd FROM table;
As to why your DELETE didn't work, perhaps those NULL's aren't NULL. Perhaps they hold a TAB character or 50 spaces? In which case #sidux's comment on your Q would do the trick. Trimming the field and looking where its value is =''.

Maybe something like this:
select
isnull(no,'')+isnull(no19,'')+isnull(no68,''),
a,b,c,d
from book1
That should concatenate all token in a row (and only one from no, no19 and no68 will have a value).

I created a table 'foo' with 3 text columns, like so:
column1 column2 column3
------- ------- -------
row1 3371522572594880 3373608476884750
row2 asdfasdf asdfasdf
row3 3387452540705400 3388486878919450
Then executed the query
select token from(
select column1 as token from foo where column1 != ''
union all
select column2 as token from foo where column2 != ''
union all
select column3 as token from foo where column3 != ''
)
And got the result:
token
3371522572594880
asdfasdf
3387452540705400
3388486878919450
3373608476884750
asdfasdf
Is that what you're after?

Related

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;

Create duplicates with 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

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%' )

Querying Same Lookup Table With Multiple Columns

I'm a bit confused on this. I have a data table structured like this:
Table: Data
DataID Val
1 Value 1
2 Value 2
3 Value 3
4 Value 4
Then I have another table structured like this:
Table: Table1
Col1 Col2
1 2
3 4
4 3
2 1
Both columns from Table1 point to the data in the data table. How can I get this data to show in a query? For example, a query to return this:
Query: Query1
Column1 Column2
Value 1 Value 2
Value 3 Value 4
Value 4 Value 3
Value 2 Value 1
I'm familiar enough with SQL to do a join with one column, but lost beyond that. Any help is appreciated. Sample sql or a link to something to read. Thanks!
PS: This is in sqlite
You can join the same table twice:
Select
d1.val As column1,
d2.val As column2
From table1 t
Join data d1 On ( d1.dataId = t.col1 )
Join data d2 On ( d2.dataId = t.col2 )