Is it possible to include dual table in a join query - sql

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(+)

Related

(Teradata Version)- get all records plus all corresponding records in another table

Can following Query be optimised for Teradata?
We need all records from small table A, plus all corresponding records from large table B, that match on a nonunique key
Or, in other words: everything except all from B that has no match in A.
Maybe something with a JOIN? Or a Subselect that is a non-correlated Query, does that also apply to Teradata?
SELECT a.nonunique
, a.colX
FROM small_tab a
UNION ALL
SELECT b.nonunique
, b.colY
FROM large_tab b
WHERE EXISTS (
SELECT 1
FROM small_tab a
WHERE a.nonuniqe = b.nonunique
);
Thanks for the help!
=========UPDATE====
based on quanos answer in this MySQL question, would following statement with a noncorrelated subquery be faster also in Teradata?
SELECT a.nonunique
, a.colX
FROM small_tab a
UNION ALL
SELECT b.nonunique
, b.colY
FROM large_tab b
WHERE b.nonunique IN
(
SELECT DISTINCT nonunique
FROM small_tab
GROUP BY nonunique
)
I cannot test in Teradata currently, only have an Oracle instance at home..
I'm not sure whether it is a typo, but you have a redundant select query after WHERE clause. Also, you will have to use the same column name in SELECT query that is being used in WHERE Claue.
Below query works fine in Teradata.
SELECT a.nonunique, a.colX
FROM small_tab a
UNION ALL
SELECT b.nonunique, b.colY
FROM large_tab b
WHERE b.id IN(
SELECT **id**
FROM small_tab)
Hope it helps. if any query on above query, please let me know.

how to select a list of 10,000 unique ids from dual in oracle SQL

So I can't create or edit tables (I'm a user with read only permission) and I want to look up 10,000 unique id's. I can't put them inside of an IN() statement because oracle limits over 1000 items.
Is it possible to select this entire list from the DUAL table in oracle? Something like:
select
'id123,id8923,id32983,id032098,id308230,id32983289'
from DUAL
Use a collection (they are not limited to 1000 items like an IN clause is):
SELECT COLUMN_VALUE AS id
FROM TABLE(
SYS.ODCIVARCHAR2LIST(
'id123', 'id8923', 'id32983', 'id032098', 'id308230', 'id32983289'
)
)
SYS.ODCIVARCHAR2LIST and SYS.ODCINUMBERLIST are collection types that are supplied in the SYS schema.
You can join this directly to whichever table you are SELECTing from without needing to use the DUAL table:
SELECT y.*
FROM your_table y
INNER JOIN TABLE(
SYS.ODCIVARCHAR2LIST(
'id123', 'id8923', 'id32983', 'id032098', 'id308230', 'id32983289'
)
) i
ON (y.id = i.COLUMN_VALUE);
If you can get a collection type created then you do not even need the TABLE expression and can use it directly in the WHERE clause using the MEMBER OF operator:
CREATE OR REPLACE TYPE stringlist IS TABLE OF VARCHAR2(200);
/
SELECT *
FROM yourtable
WHERE id MEMBER OF stringlist(
'id123', 'id8923', 'id32983', 'id032098', 'id308230', 'id32983289'
);
You can even pass the values as a bind parameter - see my answer here
Oracle still doesn't support the VALUES row constructor, so there are only two ugly workarounds:
The 1000 item limit does not apply for multi-column IN conditions
Expression Lists
A comma-delimited list of expressions can contain no more than 1000
expressions. A comma-delimited list of sets of expressions can contain
any number of sets, but each set can contain no more than 1000
expressions.
so you can do:
where (1,id) in ( (1,'id123'),
(1,'id8923'),
(1,'id32983'),
(1,'id032098'), .... )
Or using a big ugly UNION ALL:
with idlist (xid) as (
select 'id123' from dual union all
select 'id8923' from dual union all
.....
select 'id32983' from dual
)
select ...
from some_table
where id in (select xid from idlist);
One solution is the WITH clause:
with ids as (
select 'id123' as uid from dual union all
select 'id8923' as uid from dual union all
select 'id32983' as uid from dual union all
select 'id032098' as uid from dual union all
select 'id308230' as uid from dual union all
select 'id32983289' as uid from dual
)
select *
from ids
join your_table yt
on yt.id = ids.uid
This may seem like a bit of a chore but presumably you have your list of UIDs in a spreadsheet or whatever. If so it's a cinch to generate those select statements using regular expressions. Just cut'n'paste the column into an editor which supports regex search and replace.
Yet another work-around
select *
from t
where id in ('id1','id2','id3',...,'id1000')
or id in ('id1001','id1002','id1003',...,'id2000')
or id in ('id2001','id2002','id2003',...,'id3000')
or ...

Matching a substring to a string

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

How to create temporary result set from selected set of data in SQL?

For debugging purpose I want to create pseudo "result set" in order to join them, like:
with tmp_tbl as ( select v from dual where v in ('cat', 'dog', 'fish') )
select read_tbl.* from tmp_tbl
left outer join read_tbl on real_tbl.id = tmp_tbl.id;
I understand that above expression is invalid and can be transformed into another which works. But my real example too complicate to shown here.
My question how to make this expression:
select v from dual where v in ('cat', 'dog', 'fish')
a valid result set so I can use it with joins and from keywords?
dual doesn't have v column. I look for a way to break SQL syntax to avoid create table calls..
I'm still not quite sure what you're trying to do, but it looks to me like you want a dummy table with fixed values. If so you can select multiple dummy values from dual and union all the results, which will give you multiple rows. You can then use that as a sub-select, or if you're effectively masking a real table (from the 'debug' comment) then a CTE might be clearer:
with tmp_tbl as (
select 'cat' as id from dual
union all select 'dog' from dual
union all select 'fish' from dual
)
select tmp_tbl.id, read_tbl.*
from tmp_tbl
left outer join real_tbl
on real_tbl.id = tmp_tbl.id;
You referred to a v column in the text, but you're joining on id, so I've aliased the fixed value as id inside the CTE (it only needs to be named in the first row). You can just change that to something else if you prefer. And you can of course select several fixed values (with different aliases) in each select from dual to make it look more like a real table.
For this purpose you can use subquery factoring, also known as “the with clause”
with t as
( select v from dial where v in ('cat','dog','fish') )
Select * from t
Oracle may decide to materialize this result set internally or not. If you want to control this behavior, you can use the optimizer hints “materialize” and “inline”.
Hope this helps.
Regards,
Rob.
Just enclose the query in brackets and give it a name, than you can use it in joins as you wish:
SELECT *
FROM ( select v from dial where v in ('cat', 'dog', 'fish') ) tmp_table
JOIN other_table ON tmp_table.v = other_table.v
WHERE tmp_table.v = xxx etc

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