Alternative for Cartesian and Cross Join - sql

I want to output all the possible combination in two tables without using cartesian join or cross join. Is this possible?

I want to output all the possible combination in two tables without using cartesian join or cross join. Is this possible?
By a strict definition level, it is not possible. Why? Because the definition of a Cartesian product is exactly what you describe (the term "Cartesian join" is not often used but is a synonym for "Cartesian product"). Hence, any method that you use is implementing this functionality. Normally this functionality is implementing using CROSS JOIN (and I reluctantly admit, sometimes using ,).
You might say "add 1 to a number without doing + 1". Someone else comes along and says "use + 2 - 1". Well, that is adding one, but just using two operations rather than one.
If you want a Cartesian product but you don't want to use the CROSS JOIN operator, the most typical method uses ON 1=1:
select t1.*, t2.*
from t1 join
t2
on 1 = 1;

All possible combinations is the definition of a cartesian product.
Here are 3 alternatives to get a cartesian product from two tables.
All 3 alternatives eventually boils down to a cross join (and execution plan is the same for all 3):
Create and populate sample tables:
CREATE TABLE t1
(
int_col int
)
CREATE TABLE t2
(
char_col char(1)
)
INSERT INTO t1 VALUES
(1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
INSERT INTO t2 VALUES
('a'), ('b'), ('c'), ('d'), ('e'), ('f'), ('h'), ('i'), ('j'), ('k')
The queries:
An implicit cross join:
SELECT *
FROM t1, t2
An explicit cross join:
SELECT *
FROM t1
CROSS JOIN t2
Cross apply:
SELECT *
FROM t1
CROSS APPLY t2
All results are the same:
int_col char_col
1 a
2 a
3 a
4 a
5 a
6 a
7 a
8 a
9 a
10 a
1 b
2 b
3 b
4 b
5 b
6 b
7 b
8 b
9 b
10 b
1 c
2 c
3 c
4 c
5 c
6 c
7 c
8 c
9 c
10 c
1 d
2 d
3 d
4 d
5 d
6 d
7 d
8 d
9 d
10 d
1 e
2 e
3 e
4 e
5 e
6 e
7 e
8 e
9 e
10 e
1 f
2 f
3 f
4 f
5 f
6 f
7 f
8 f
9 f
10 f
1 h
2 h
3 h
4 h
5 h
6 h
7 h
8 h
9 h
10 h
1 i
2 i
3 i
4 i
5 i
6 i
7 i
8 i
9 i
10 i
1 j
2 j
3 j
4 j
5 j
6 j
7 j
8 j
9 j
10 j
1 k
2 k
3 k
4 k
5 k
6 k
7 k
8 k
9 k
10 k

Related

SQL outer join on two columns, returning null in one column if only the other matches

I couldn't find exactly what I'm looking for in another thread.
Let's say I have these two tables:
left:
x
left_y
a
1
a
2
b
4
b
5
right:
x
right_y
a
2
a
3
b
5
b
6
I want to run a query close to this in intention:
SELECT *
FROM left FULL OUTER JOIN right
ON (left.x = right.x AND left.left_y = right.right_y)
OR left.x = right.x
And get an output that has no nulls in x, but maybe has a null in left_y or right_y
x
left_y
right_y
a
1
null
a
2
2
a
null
3
b
4
null
b
5
5
b
null
6
You can use coalesce:
select coalesce(l.x, r.x) as x,
left_y,
right_y
from l full outer join r
on l.x = r.x
and l.left_y = r.right_y
Fiddle

Excluding Certain Matching Rows in an SQL Join

My issue somewhat complex, so I will explain using simplified versions of my tables.
This is Table 1:
Value L AID OID
A 1 1
B 2 1
C 3 1
D 4 1
E 2 1
F 2 2
G 2 3
H 2 4
This is Table 2:
Value R AID OID VAR
Z 0 1 0
Y 1 1 1
X 2 1 1
W 4 1 1
V 0 2 0
U 1 2 1
T 3 2 1
I would like to join these tables such that any row in Table 1 that doesn’t have a corresponding row in Table 2 with both matching AID and OID is returned in a join to the row with a matching OID and an AID and VAR of 0. In this example it would look like this:
Value L Value R AID OID VAR
C Z 3 1 0
F V 2 2 0
H V 4 2 0
I am not certain how to tackle this. Specifically, not sure how to stop the rows that have a matching AID and OID from showing up in my join, and only having the rows that don't have that match. Any advice would be appreciated.
I think you want not exists:
select t1.*
from table1 t1
where not exists (select 1
from table2 t2
where t2.aid = t1.aid and t2.oid = t1.oid and t2.var = 0
);

sql server table data into parent child table

Name group subgroup
--------------------------
A B C
A B D
A E F
A E G
H I J
H I K
H L M
H L N
into
ID Name ParentID
----------------------
1 A NULL
2 B 1
3 C 2
4 D 2
5 E 1
6 F 5
7 G 5
8 H NULL
9 I 8
10 J 9
11 K 9
12 L 8
13 M 12
14 N 12
INSERT INTO NEWTAB("Name")
SELECT DISTINCT "Name"
FROM TAB;
INSERT INTO NEWTAB("Name", "ParentID")
SELECT DISTINCT C."group", P."ID"
FROM TAB C
LEFT JOIN NEWTAB P
ON C."Name" = P."Name";
INSERT INTO NEWTAB("Name", "ParentID")
SELECT DISTINCT C."subgroup", P."ID"
FROM TAB C
LEFT JOIN NEWTAB P
ON C."group" = P."Name";

Hiding a row where value = 0 but count its other column values in total calculations - sql2008

I have tables like that: (C1-C2 varchar(10), C3-Number int)
WaitingData
C1 C2 C3 Number
A B 1 10
A B 2 0
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
A B 3 0
X B 4 12
I am using the query below to represent the data:
Select wd.C1,wd.C2,wd.C3,wd.Number as NW,cdd.Number as NC
into #AllData
from (Select C1,C2,C3,sum(Number) from WaitingData group by C1,C2,C3) wd
outer apply (Select C1,C2,C3,sum(Number)
from CompletedData cd
where wd.C1=cd.C1 and wd.C2=cd.C2 and wd.C3=cd.C3
) cdd
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NW)
from #AllData
This is giving me an output like:
C1 C2 C3 NW NC
A B 1 10 5
A B 2 0 2
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
However, I want to hide the rows that has no NW but calculate its regarding values while calculating the Total row (see NC below). The output I want is like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
I could not find a way to provide an output like this. Any help would be so appreciated!
------------------------------EDIT---------------------------------------
------------------------------EDIT---------------------------------------
When I have data in the tables like below, the outer apply is not working like I want, it does not include the data A B 2.
WaitingData
C1 C2 C3 Number
A B 1 10
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
X B 4 12
And the output would be like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 NULL
X B 4 2 12
Total Total -1 16 17
In this situation, what can I do to count "2" NC value having by A B 2 on the final result and see NC as 19 instead 17, except inserting all the records that included by CompletedData but WaitingData? (need an efficient way)
Wrap the final result with one more select and exclude rows where NW = 0.
select * from
(
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from #AllData
) t
where NW <> 0
Edit: Using a full join to get all values from both tables.
with t as
(select coalesce(w.c1,c.c1) as c1,coalesce(w.c2,c.c2) as c2,coalesce(w.c3,c.c3) as c3
, coalesce(w.number,0) as nw , coalesce(c.number,0) as nc
from waitingdata w
full join completeddata c on w.c1 = c.c1 and w.c2=c.c2 and w.c3=c.c3)
select * from
(select * from t
union all
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from t) x where nw <> 0
You can do all of this in one query, without temporary tables, intermediate results, subqueries, or UNION by using the ROLLUP operator:
SELECT
WD.C1,
WD.C2,
WD.C3,
SUM(WD.Number) AS NW,
SUM(CD.Number) AS NC
FROM
dbo.WaitingData WD
LEFT OUTER JOIN CompletedData CD ON
CD.C1 = WD.C1 AND
CD.C2 = WD.C2 AND
CD.C3 = WD.C3
GROUP BY
WD.C1,
WD.C2,
WD.C3
WITH ROLLUP
HAVING
GROUPING_ID(WD.C1, WD.C2, WD.C3) IN (0, 7) AND
SUM(WD.Number) <> 0

DB Select - Logic Meltdown

I've been struggling with this one for a while.
[sample table]
ITEM GROUP
---- -----
4 A
7 A
3 A
8 A
7 B
6 B
9 B
0 C
4 C
2 C
5 C
4 C
7 C
5 D
9 D
2 E
7 E
1 E
4 E
7 F
3 F
9 F
6 F
8 G
4 H
5 H
3 H
9 H
0 H
8 H
I need an sql query that will tell me how many times each "ITEM", on a range of SELECT DISTINCT ITEM appeared with one another in a particular group.
IE:
Items 4 and 8 appeared 2 times (groups A and H).
Items 0 and 4 appeared 2 times (groups C and H).
Items 7, 6 and 9 appeared appeared 2 times (groups B and F).
..And do on. It's ok to ignore "rogue" items that only appear in one group.
Can it be done? Thanks
This will work for pairs of items:
SELECT T1.item, T2.item, COUNT(*)
FROM yourTable T1
JOIN yourTable T2
ON T1.item < T2.item
AND T1.group = T2.group
GROUP BY T1.item, T2.item