Matching a substring to a string - sql

Please advise me on the following question:
I have two tables in an Oracle db, one that contains full numbers and the other that contains parts of them.
Table 1:
12323543451123
66542123345345
16654232423423
12534456353451
64565463345231
34534512312312
43534534534533
Table 2:
1232
6654212
166
1253445635
6456546
34534
435345
Could you please suggest a query that joins these two tables and shows the relation between 6456546 and 64565463345231, for example. The main thing is that Table 2 contains a lot more data than Table 1, and i need to find all the substrings from Table 2 that are not present in Table 1.
Thanks in advance!

Try this:
with t as (
select 123 id from dual union all
select 567 id from dual union all
select 891 id from dual
), t2 as (
select 1112323 id from dual union all
select 32567321 id from dual union all
select 44891555 id from dual
)
select t.id, t2.id
from t, t2
where t2.id||'' like '%'||t.id||'%'

You could try using the CONTAINS operator like this :
SELECT * FROM Table2 JOIN Table1 ON Table1.id=Table2.id
WHERE NOT CONTAINS (Table2.data, Table1.data)

Are numbers from table two in a set place in table 1? For example is the 1232 in the same place each time or do you have to search a sting for the numbers. If it's set you could use an inline select or a temp table and create a substring of the string your searching and then join the table or temp table on that field.

you first need to say if the number in Table 1 and 2 are repeated, if is not then I think this query would help you:
SELECT *
FROM Table_1
JOIN Table_2 ON Table_1.ID = Table_2.ID
WHERE Table_2.DATA LIKE Table_1.DATA

Related

How would I store the result of a select statement so that I can reuse the results to join to different tables?

How would I store the result of a select statement so that I can reuse the results to join to different tables? This will also be inside a cursor.
Below is some pseudo code, in this example I have kept the Select statement simple but in real life it is a long query with multiple joins, I have to use the identical SQL twice to join to 2 different tables and as it is quite long and can be changed in the future hence I want to be able reuse it.
I have tried creating a view and storing the results of the select statement in it but it seems I can't create a view inside the cursor loop, when I tried I am getting "Encountered the symbol "CREATE"" error.
DECLARE TYPE cur_type IS REF CURSOR;
CURSOR PT_Cursor IS
SELECT * FROM Table1
PT_Cursor_Row PT_Cursor%ROWTYPE;
BEGIN
OPEN PT_Cursor;
LOOP
FETCH PT_Cursor INTO PT_Cursor_Row;
EXIT WHEN PT_Cursor%NOTFOUND;
Select ID From Table2 --this is actually a long complext query
INNER JOIN Table3 ON Table2.ID = Table3.ID
WHERE Table2.ID = PT_Cursor_Row.ID
Select * From Table2 --this is actually a long complext query
LEFT JOIN Table4 ON Table2.ID = Table4.ID
WHERE Table2.ID = PT_Cursor_Row.ID
END LOOP;
CLOSE PT_Cursor;
END;
One way to save the results from a query is via a temporary table - there's a short answer to this question that describes how to create them, while there is a longer answer here that discusses how to use them, with possible alternatives.
Temp tables certainly are a viable option.
One can also use the with statement to 'reuse' results sets.
WITH
PEOPLE AS
(
SELECT 'FRED' NAME, 12 SHOE_SIZE FROM DUAL UNION ALL
SELECT 'WILMA' NAME, 4 SHOE_SIZE FROM DUAL UNION ALL
SELECT 'BARNEY' NAME, 10 SHOE_SIZE FROM DUAL UNION ALL
SELECT 'BETTY' NAME, 3 SHOE_SIZE FROM DUAL
),
WOMAN AS
(
SELECT 'BETTY' NAME FROM DUAL UNION ALL
SELECT 'WILMA' NAME FROM DUAL
)
SELECT 'WOMANS ', PEOPLE.NAME, PEOPLE.SHOE_SIZE
FROM PEOPLE, WOMAN
WHERE PEOPLE.NAME = WOMAN.NAME
UNION ALL
SELECT 'MENS ', PEOPLE.NAME, PEOPLE.SHOE_SIZE
FROM PEOPLE, WOMAN
WHERE PEOPLE.NAME = WOMAN.NAME(+)
AND WOMAN.NAME IS NULL

SQL Join Issue return DISTINCT Names

I have the following two tables with data like so:
Table Values
var_label
1
2
2
1
3
Table Codes
var_code
1
2
4
2
I need to join these tables and get the distinct result. The var_label and var_code are equal pieces of data. I want to have the joined output like so:
MyColumn
1
2
3
4
Wht's the best way to do this?
Use UNION without ALL(implicit distinct) like so:
SELECT var_label AS MyColumn
FROM Values
UNION
SELECT var_code
FROM Codes
Live Demo
SELECT var_label
FROM Table1 as MyColumn
UNION
SELECT var_data as MyColumn
FROM Table2
you can give aliases for getting only one colum name.
SQLFiddle DEMO
SELECT distinct(var_label)
FROM Table1
UNION
SELECT distinct(var_data)
FROM Table2

Is it possible to include dual table in a join query

Is it possible to include the DUAL table in a join query ?
Can anyone give me an example which includes the SYSTIMESTAMP from dual table.
One common use (for me) is to use it to make inline views to join on...
SELECT
filter.Title,
book.*
FROM
(
SELECT 'Red Riding Hood' AS title FROM dual
UNION ALL
SELECT 'Snow White' AS title FROM dual
)
AS filter
INNER JOIN
book
ON book.title = filter.title
[This is a deliberately trivialised example.]
Basically you can but there's no need to.
you can add the systimestamp pseudo column to whatever query you already have:
SELECT t.col1, t.col2, systimestamp
FROM your_table t
Will give same results as
SELECT t.col1, t.col2, d.st
FROM your_table t, (select systimestamp st from dual) d
Note that the dual table has only one line, so the cartessian product will not add rows to your original query.
Try this solution:
select (select SYSTIMESTAMP from dual ) as d
/*
Here you can add more columns from table tab
*/
from tab
There should be no need to, DUAL keyword is a way of saying that you're not querying a table, if you want to "join" DUAL with an other table, just query the other table including your columns that don't come from the table in the select clause.
EDIT : As the comments says, this statement is false, DUAL is a table.
I still think there is no point in including (from the question)
the DUAL table in a join
You CAN do this in Oracle. I found this question while trying to solve a similar problem. The trick is to wrap DUAL in a subquery, and return a static value which you can join on.
In my case, I wanted to see if a record meeting some conditions existed in a table before inserting a new record. If it existed, I wanted the ID column. If it did not exist, I wanted a new ID value from a sequence. I used DUAL to "fake" an outer join so that I would always get a row back. Then I used NVL() to return a sequence value if the result was null.
SELECT NVL(v.ID, REAL_SEQUENCE.nextval)
FROM (SELECT 1 as match FROM DUAL) d,
(SELECT 1 as match, ID
FROM REAL_TABLE
WHERE CONDITION = CRITERIA) v
WHERE d.match = v.match(+)

Display multiple queries with different row types as one result

In PostgreSQL 8.3 on Ubuntu, I do have 3 tables, say T1, T2, T3, of different schemas.
Each of them contains (a few) records related to the object of the ID I know.
Using 'psql', I frequently do the 3 operations:
SELECT field-set1 FROM T1 WHERE ID='abc';
SELECT field-set2 FROM T2 WHERE ID='abc';
SELECT field-set3 FROM T3 WHERE ID='abc';
and just watch the results; for me it is enough to see.
Is it possible to have a procedure/function/macro etc, with one parameter 'id',
just running the three SELECTS one after another,
displaying results on the screen ?
field-set1, field-set2 and field-set 3 are completely different.
There is no reasonable way to JOIN the tables T1, T2, T3; these are unrelated data.
I do not want JOIN.
I want to see the three resulting sets on the screen.
Any hint?
Quick and dirty method
If the row types (data types of all columns in sequence) don't match, UNION will fail.
However, in PostgreSQL you can cast a whole row to its text representation:
SELECT t1:text AS whole_row_in_text_representation FROM t1 WHERE id = 'abc'
UNION ALL
SELECT t2::text FROM t2 WHERE id = 'abc'
UNION ALL
SELECT t3::text FROM t3 WHERE id = 'abc';
Only one ; at the end, and the one is optional with a single statement.
A more refined alternative
But also needs a lot more code. Pick the table with the most columns first, cast every individual column to text and give it a generic name. Add NULL values for the other tables with fewer columns. You can even insert headers between the tables:
SELECT '-t1-'::text AS c1, '---'::text AS c2, '---'::text AS c1 -- table t1
UNION ALL
SELECT '-col1-'::text, '-col2-'::text, '-col3-'::text -- 3 columns
UNION ALL
SELECT col1::text, col2::text, col3::text FROM t1 WHERE id = 'abc'
UNION ALL
SELECT '-t2-'::text, '---'::text, '---'::text -- table t2
UNION ALL
SELECT '-col_a-'::text, '-col_b-'::text, NULL::text -- 2 columns, 1 NULL
UNION ALL
SELECT col_a::text, col_b::text, NULL::text FROM t2 WHERE id = 'abc'
...
put a union all in between and name all columns equal
SELECT field-set1 as fieldset FROM T1 WHERE ID='abc';
union all
SELECT field-set2 as fieldset FROM T2 WHERE ID='abc';
union all
SELECT field-set3 as fieldset FROM T3 WHERE ID='abc';
and execute it at once.

find the missing values from a set of values, using SQL

How can I find a missing values from a set of values, using SQL (Oracle DB)
e.g.
SELECT NAME
FROM ACCOUNT
WHERE ACCOUNT.NAME IN ('FORD','HYUNDAI','TOYOTA','BMW'...)
(The "IN" clause may contain hundreds of values)
If 'HYUNDAI' is missing in the ACCOUNT table, I need to get the result as "HYUNDAI".
Currently I use the result of the above query to do a Vlookup against the original set of values to find the missing values, I want to directly get the missing values without doing the Vlookup.
Thanks
Kiran,
You got it reversed. Do this: http://www.sqlfiddle.com/#!2/09239/3
SELECT Brand
FROM
(
-- Oracle can't make a row without a table, need to use DUAL dummy table
select 'FORD' as Brand from dual union
select 'HYUNDAI' from dual union
select 'TOYOTA' fom dual union
select 'BMW' from dual
) x
where Brand not in (select BrandName from account)
Sample Account data:
create table account(AccountId int, BrandName varchar(10));
insert into account(AccountId, BrandName) values
(1,'FORD'),
(2,'TOYOTA'),
(3,'BMW');
Output:
| BRAND |
-----------
| HYUNDAI |
Better yet, materialized the brands to a table:
select *
from Brand
where BrandName not in (select BrandName from account)
Output:
| BRANDNAME |
-------------
| HYUNDAI |
Sample data and live test: http://www.sqlfiddle.com/#!2/09239/1
CREATE TABLE Brand
(`BrandName` varchar(7));
INSERT INTO Brand
(`BrandName`)
VALUES
('FORD'),
('HYUNDAI'),
('TOYOTA'),
('BMW');
create table account(AccountId int, BrandName varchar(10));
insert into account(AccountId, BrandName) values
(1,'FORD'),
(2,'TOYOTA'),
(3,'BMW');
You should use Except: EXCEPT returns any distinct values from the left query that are not also found on the right query.
WITH SomeRows(datacol) --It will look for missing stuff here
AS( SELECT *
FROM ( VALUES ('FORD'),
('TOYOTA'),
('BMW')
) AS F (datacol)),
AllRows (datacol) --This has everthing
AS( SELECT *
FROM ( VALUES ('FORD'),
('HYUNDAI'),
('TOYOTA'),
('BMW')
) AS F (datacol))
SELECT datacol
FROM AllRows
EXCEPT
SELECT datacol
FROM SomeRows
You can do:
SELECT a.val
FROM
(
SELECT 'FORD' val UNION ALL
SELECT 'HYUNDAI' UNION ALL
SELECT 'TOYOTA' UNION ALL
SELECT 'BMW' UNION ALL
etc...
etc...
) a
LEFT JOIN account b ON a.val = b.name
WHERE b.name IS NULL
This worked perfectly, thanks Michael.
SELECT Brand
FROM
( -- Oracle can't make a row without a table, need to use DUAL dummy table
select 'FORD' as Brand from dual union
select 'HYUNDAI' from dual union
select 'TOYOTA' fom dual union
select 'BMW' from dual
)
where Brand not in (select BrandName from account)
Luxspes and Zane thank you for your inputs
Contributing Excel code to make the typing of the answer easier:
Say column A has the values (Ford, Hyundai,...).
In column B, put this in every cell:
select 'x' as brand from dual union
In column C, write this formula, and copy it down.
=REPLACE(A2,9,1,A1)
All of the select/union statements should appear in column C.