How to cross join with out using a table? - sql

Recently, I am trying to create a table. I have a column that contains 'a', 'b', 'c' and would like to cross join it with 1,2,3 in to the table below.
However, I don't have a table that contains values 1,2,3 and need to do it without creating a table.
Can I achieve this without creating any table? Thanks a lot!
Col1
a
b
c
Col1 Col2
a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3

Use a CTE instead:
SQL> with
2 a (col) as
3 (select 'a' from dual union all
4 select 'b' from dual union all
5 select 'c' from dual
6 ),
7 b (col) as
8 (select 1 from dual union all
9 select 2 from dual union all
10 select 3 from dual
11 )
12 select a.col, b.col
13 from a cross join b;
C COL
- ----------
a 1
a 2
a 3
b 1
b 2
b 3
c 1
c 2
c 3
9 rows selected.
SQL>

You can use:
SELECT *
FROM table1
CROSS JOIN (SELECT LEVEL AS col2 FROM DUAL CONNECT BY LEVEL <= 3);
or
WITH data (col1, col2) AS (
SELECT col1, 1 FROM table1
UNION ALL
SELECT col1, col2 + 1 FROM data WHERE col2 < 3
)
SELECT * FROM data;
Which, given your sample data:
CREATE TABLE table1 (col1) AS
SELECT 'a' FROM DUAL UNION ALL
SELECT 'b' FROM DUAL UNION ALL
SELECT 'c' FROM DUAL;
Both output:
COL1
COL2
a
1
b
1
c
1
a
2
b
2
c
2
a
3
b
3
c
3
db<>fiddle here

You can create "tables" within your query in many different ways, several of which have been illustrated in other answers already.
For your request I like an XML solution as shown below:
create table table1 (col1 varchar2(1));
insert into table1(col1) values('a');
insert into table1(col1) values('b');
insert into table1(col1) values('c');
commit;
select t1.col1, xmlcast(column_value as number) as col2
from table1 t1 cross join xmltable('1 to 3')
;
COL1 COL2
---- ----
a 1
a 2
a 3
b 1
b 2
b 3
c 1
c 2
c 3

Related

How can I select a data from another column from rows that have been selected?

I tried my best to figure and google this out, but couldn't really find a solid answer to it.
The problem I'm facing is that
Table 1:
ID Value 1
1 a
2 b
3 c
Table 2:
ID Value 2
1 4a
3 5b
4 6c
and I'd basically have to select the value from Table 1 that doesn't exist on Table 2 (Thus, 'b')
I can select and identify the ID that I want by using minus function between the tables, but can't seem to figure out a way to call a query to instead call the data.
Use the MINUS as a subquery (i.e. an inline view) (lines #14 - 16):
Sample data:
SQL> with
2 table1(id, value1) as
3 (select 1, 'a' from dual union all
4 select 2, 'b' from dual union all
5 select 3, 'c' from dual
6 ),
7 table2 (id, value2) as
8 (select 1, '4a' from dual union all
9 select 3, '5b' from dual union all
10 select 4, '6c' from dual
11 )
Query begins here:
12 select a.*
13 from table1 a
14 where a.id in (select t1.id from table1 t1
15 minus
16 select t2.id from table2 t2
17 );
ID VALUE1
---------- ----------
2 b
SQL>
Alternatively, use not exists:
<snip>
12 select a.*
13 from table1 a
14 where not exists (select null
15 from table2 b
16 where b.id = a.id
17 );
ID VALUE1
---------- ----------
2 b
SQL>

SQL Group by fixed list of values

If I have two columns:
col1 col2 amount
1 2 15
2 3 12
1 3 10
3 1 4
3 2 3
And I perform a group by col1,col2 then I get a row for each combination (present) in the data.
My problem though is, that I dont always have all combinations, but I would want to return a row of each combination still. So if there isn't a combination. for example 2 -> 1 then I would want its value to be 0.
Can I somehow specify the "levels" of the group by?
I'm using SQL Oracle.
and the outcome I would want is:
1 -> 2 15
1 -> 3 10
2 -> 1 0
2 -> 3 12
3 -> 1 4
3 -> 2 3
With their respective amount, and 0 if they dont exist, or null works. ( I have a filter to exclude where col1 and col2 are same)
Generate all the rows using cross join and then filter for the ones you want:
select c1.col1, c2.col2, coalesce(t.amount, 0)
from (select 1 as co1l from dual union all
select 2 as co1l from dual union all
select 3 as co1l from dual
) c1 cross join
(select 1 as co12 from dual union all
select 2 as co12 from dual union all
select 3 as co12 from dual
) c2 left join
t
on t.col1 = c1.col1 and t.col2 = c2.col2
where c1.col1 <> c2.col2;

How to exclude certain rows from sql select

How do I exclude certain rows?
For example, I have the following table:
+------+------+------+
| Col1 | Col2 | Col3 |
+------+------+------+
| 1 | 1 | R |
| 1 | 2 | D |
| 2 | 3 | R |
| 2 | 4 | R |
| 3 | 5 | R |
| 4 | 6 | D |
+------+------+------+
I need to select only:
| 2 | 3 | R |
| 2 | 4 | R |
| 3 | 5 | R |
My select that does not work properly:
with t (c1,c2,c3) as(
select 1 , 1 , 'R' from dual union all
select 1 , 2 , 'D' from dual union all
select 2 , 3 , 'R' from dual union all
select 2 , 4 , 'R' from dual union all
select 3 , 5 , 'R' from dual union all
select 4 , 6 , 'D' from dual),
tt as (select t.*,count(*) over (partition by c1) cc from t ) select * from tt where cc=1 and c3='R';
Thanks in advance!
select * from table where col2 = 'R'
or if you want to exclude rows with D value just
select * from table where col2 != 'D'
It depends on your requirements but you can do in this way:
SELECT * FROM `table` WHERE col1 = 2 AND col3 = "R"
if you want to exclude just do it like WHERE col1 != 1
You ca also use IN clause also e.g.
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1, value2, ...);
This syntax is for MySql, but you can modify it as per your requirement or database you are using.
this will work :
select * from (select * from table_name) where rownum<=4
minus
select * from ( select * from table_name) where rownum<=2
My guess is that you want all rows for a col1 where no row for a col1 = D and at least 1 row for a col1 = R. # where [not] exists may do
DROP TABLE T;
CREATE TABLE T
(Col1 NUMBER, Col2 NUMBER, Col3 VARCHAR(1));
INSERT INTO T VALUES ( 1 , 1 , 'R');
INSERT INTO T VALUES ( 1 , 2 , 'D');
INSERT INTO T VALUES ( 2 , 3 , 'R');
INSERT INTO T VALUES ( 2 , 4 , 'R');
INSERT INTO T VALUES ( 3 , 5 , 'R');
INSERT INTO T VALUES ( 3 , 6 , 'D');
INSERT INTO T VALUES ( 4 , 5 , 'X');
INSERT INTO T VALUES ( 4 , 6 , 'Y');
INSERT INTO T VALUES ( 5 , 6 , 'X');
INSERT INTO T VALUES ( 5 , 5 , 'R');
INSERT INTO T VALUES ( 5 , 6 , 'Y');
SELECT *
FROM T
WHERE NOT EXISTS(SELECT 1 FROM T T1 WHERE T1.COL1 = T.COL1 AND COL3 = 'D') AND
EXISTS(SELECT 1 FROM T T1 WHERE T1.COL1 = T.COL1 AND COL3 = 'R');
Result
COL1 COL2 COL3
---------- ---------- ----
5 6 X
5 5 R
5 6 Y
2 3 R
2 4 R
use row_number() window function
with t (c1,c2,c3) as(
select 1 , 1 , 'R' from dual union all
select 1 , 2 , 'D' from dual union all
select 2 , 3 , 'R' from dual union all
select 2 , 4 , 'R' from dual union all
select 3 , 5 , 'R' from dual union all
select 4 , 6 , 'D' from dual
),
t1 as
(
select c1,c2,c3,row_number() over(order by c2) rn from t
) select * from t1 where t1.rn>=3 and t1.rn<=5
demo link
C1 C2 C3
2 3 R
2 4 R
3 5 R
You can try using correlated subquery
select * from tablename a
from
where exists (select 1 tablename b where a.col1=b.col1 having count(*)>1)
Based on what you have provided I can only surmise that the only requirement is for COL1 to be equal to 2 or 3 in that case all you have to do is (assuming that you actually have table);
SELECT * FROM <table_name>
WHERE col1 IN (2,3);
This will give you the desired output for the particular example provided in the question. If there is a selection requirement that goes beyond retrieving data where column 1 is either 2 or 3 than a more specific or precise answer can be provided.

SQL Query Join two tables with 1-Many relation with first table row and following rows for second table values

I need help with a query/ PL/SQL procedure for below requirement.
Table 1:
T1ID T1Name T1Col2
1 Name1 X
2 Name2 Y
Table2 :
T2T1ID T2SubName T2Column2
1 Test1Sub1 P
1 Test1Sub2 P
1 Test1Sub3 P
2 Test2Sub1 Q
2 Test2Sub2 Q
I want to build a query which will fetch me
T1ID T1Name T1Col2 T2SubName T2Column2
1 Test1 X
Test1Sub1 P
Test1Sub2 P
Test1Sub3 P
2 Test2 Y
Test2Sub1 Q
Test2Sub1 Q
Such a "break" layout is easily achieved by any reporting tool. In SQL*Plus, BREAK (who'd guess?) does the job. See if it helps.
SQL> break on t1id on t1name on t1col2
SQL>
SQL> with
2 t1 (t1id, t1name, t1col2) as
3 (select 1, 'name1', 'x' from dual union
4 select 2, 'name2', 'y' from dual
5 ),
6 t2 (t2t1id, t2subname, t2column2) as
7 (select 1, 'test1sub1', 'p' from dual union
8 select 1, 'test1sub2', 'p' from dual union
9 select 1, 'test1sub3', 'p' from dual union
10 select 2, 'test2sub1', 'q' from dual union
11 select 2, 'test2sub2', 'q' from dual
12 )
13 select a.t1id, a.t1name, a.t1col2, b.t2subname, b.t2column2
14 from t1 a join t2 b on b.t2t1id = a.t1id
15 order by a.t1id;
T1ID T1NAM T T2SUBNAME T
---------- ----- - --------- -
1 name1 x test1sub1 p
test1sub2 p
test1sub3 p
2 name2 y test2sub1 q
test2sub2 q
SQL>
Use FULL OUTER JOIN with proper ORDER BY statement :
select t1.t1id, nvl2(t1.t1name,'Test'||t1.t1id,'') t1name, t1.col2,
t2.t2subname, t2.t2column2
from table1 t1
full outer join table2 t2
on ( t1.col2 = t2.t2column2 )
order by nvl(t1id,2)||nvl(t2t1id,2), nvl(t2.t2subname,'0');
T1ID T1NAME COL2 T2SUBNAME T2COLUMN2
---- ------ ---- --------- ---------
1 Test1 X
Test1Sub1 P
Test1Sub2 P
Test1Sub3 P
2 Test2 Y
Test2Sub1 Q
Test2Sub2 Q
db <> fiddle demo

Sql query to print values starting from column A till column B

New to SQL so looking for help
I'm trying to write a query which would print values starting from column A till the column B excluding the value present in column 'ANS' of second table.
Like here are the two tables X and Y
Table1
A FROM TO
a 6 9
b 3 6
c 0 3
d 2 3
Table2
A ANS
a 7
b 5
c 1
And I want the output as
A ANS
a 6
a 8
a 9
b 3
b 4
b 6
c 0
c 2
c 3
d 2
d 3
I've tried to write something like this but it doesn't work
WITH y(n) AS
(SELECT 1 AS n
FROM dual
UNION ALL
SELECT n + 1 AS n
FROM y, table1 T
WHERE n <= T.TO AND n>= T.FROM )
SELECT * FROM y;
Which prints 5000+ rows (that's why I am not attaching output)
Thanks in advance
After you get all the numbers between from and to with a recursive cte, left join on the generated table and get only those numbers which don't exist in table2 using not exists.
--Get the maximum value of `to` column and generate all numbers between 0 and that value
WITH maxto(maxt) as (SELECT MAX(TO) FROM TABLE1)
,y(n) AS
(SELECT 0 AS n FROM dual
UNION ALL
SELECT n + 1 AS n FROM y WHERE n < (SELECT maxt FROM maxto))
SELECT * FROM
(SELECT t1.a, y.n
FROM y
LEFT JOIN table1 t1 on y.n between t1.from and t1.to
WHERE t1.a IS NOT NULL) x
WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE x.a = a and x.n = ans)
ORDER BY 1,2
Sample demo
WITH y(n) AS
(SELECT level - 1 FROM dual connect by level <= select max(TO- FROM) +2 from table1)
SELECT t1.a, t1.from + y.n FROM table1 t1
JOIN y on 1 = 1
left JOIN table2 on y.n + t1.FROM = t2.ANS and t2.a = t1.a
where y.n < t1.TO-t1.FROM
and t2.ANS is null;
You can use a "hierarchical query" and a MINUS operation and avoid joins altogether. MINUS is easy to understand if you are somewhat familiar with set theory. Generating numbers using hierarchical queries is somewhat unnatural (and may only be available in Oracle, I don't know any other db products), but it is used very often and it works very fast.
I changed the column names to from_n and to_n; I don't remember if "from" and/or "to" are reserved words in Oracle, but why take the risk.
with
table1 ( a, from_n, to_n ) as (
select 'a', 6, 9 from dual union all
select 'b', 3, 6 from dual union all
select 'c', 0, 3 from dual union all
select 'd', 2, 3 from dual
),
table2 ( a, ans ) as (
select 'a', 7 from dual union all
select 'b', 5 from dual union all
select 'c', 1 from dual
)
-- everything above this point is for testing only and can be removed
-- solution (SQL query) begins below
select a, from_n + level - 1 as ans
from table1
connect by level <= 1 + to_n - from_n
and prior a = a
and prior sys_guid() is not null
minus
select a, ans
from table2
;
Output:
A ANS
- ----------
a 6
a 8
a 9
b 3
b 4
b 6
c 0
c 2
c 3
d 2
d 3
11 rows selected