I would like to write an SQL script like this:
select count(*) from table1 t1 where exists (
select t2.desired_col from table2 t2 where t1.ID = t2.reference_t1_id
intersect
(2, 5, 9, 10)
);
The goal is to tell me, how many entries in t1 have at least one common value between desired_col of t2 and a given collection (i.e. (2, 5, 9, 10)). t2 has a ManyToOne relationship to t1. However, it seems I cannot intersect between a select and a simple collection. As a workaround, I wrapped the given collection like this:
select count(*) from table1 t1 where exists (
select t2.desired_col from table2 t2 where t1.ID = t2.reference_t1_id
intersect
select desired_col from table t2 where desired_col in (2, 5, 9, 10)
);
I think this solution looks a little ugly and was wondering, if there is a better way to find the intersect between a select statement and a simple collection.
You need to turn your list of IDs into an actual set, which you can then use in SQL with a table() function. Something like this:
select count(*) from table1 t1
where exists (
select t2.desired_col from table2 t2
where t1.ID = t2.reference_t1_id
intersect
select * from table(sys.odcinumberlist (2, 5, 9, 10))
);
There are several variant solutions. For instance, instead of intersection you could extend the WHERE clause with an IN subquery:
and t2.desired_col in (select * from table(sys.odcinumberlist (2, 5, 9, 10)))
or indeed
and t2.desired_col in (2, 5, 9, 10)
This uses the Oracle supplied collection type, sys.odcinumberlist, which is an array of numbers.
I have this query which does get the results I require but is incredibly slow and surely there must be a better way of doing this as I would need to run this regularly.
Each where clause has two variables which will always be the same number but I need to use this with 50+ BigIDs, the example shows 3 but I would do it for BigID 1 to 50+.
I am unsure how to make this shorter because of the two variables (one of which being in a subquery) and group by which is required.
Any help or pointing in the right direction would be appreciated. Thanks.
SELECT BigID,count(LittleID)
FROM Table1
where ( (BigID=1 and LittleID not in (SELECT LittleID FROM Table2 where BigID=1)) or
(BigID=2 and LittleID not in (SELECT LittleID FROM Table2 where BigID=2)) or
(BigID=3 and LittleID not in (SELECT LittleID FROM Table2 where BigID=3)) )
group by BigID
One method is a correlated subquery:
SELECT t1.BigID, count(t1.LittleID)
FROM Table1 t1
WHERE t1.BigID IN (1, 2, 3) and
t1.LittleID not in (SELECT t2.LittleID
FROM Table2 t2
WHERE t2.BigID = t1.BigId
)
GROUP BY t1.BigID
SELECT t1.BigID, COUNT(t1.LittleID)
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.LittleID = t2.LittleID AND t1.BigID = t2.BigID
WHERE t1.BigID IN (1, 2, 3)
AND t2.LittleID IS NULL
GROUP BY t1.BigID
SELECT Table1.BigID,
COUNT(Table1.LittleID)
FROM Table1
LEFT JOIN Table2 ON Table1.LittleID = Table2.LittleID
AND Table1.BigID = Table2.BigID
WHERE Table2.LittleID IS NULL
AND Table1.BigID IN (1, 2, 3)
GROUP BY Table1.BigID
I am trying to learn hierachial queries so I am seeing a syntax in the first where we need to initialize a seed value in the first query. My question is that should the intial seed query return only one value? or multiple values ?
Say if I need to perform recursion for multiple groups
It can return multiple values - all rows from the seed query serves as in input set for the next recursion.
For instance, with this schema
create table T1 (
p int,
c int
)
insert into T1 (p, c) values (0, 1)
insert into T1 (p, c) values (1, 2)
insert into T1 (p, c) values (2, 3)
insert into T1 (p, c) values (10, 11)
insert into T1 (p, c) values (11, 12)
insert into T1 (p, c) values (11, 13)
And this recursive query
WITH cte (p, c) as
(
select p, c from T1 where p = 0 or p = 10
union all
select T1.p, T1.c from T1
inner join cte on T1.p = cte.c
)
select * from cte
Notice that the base returns 2 rows and you get 2 branches (your multiple groups) from there.
I have two tables which I need to join/union for a distinct set - but every query I've tried so far results in too few/too many rows returned.
table one table two
ID Type
Type SubType
SubType
Percentage
Category
Table one is the main data set, table two is lookup values.
The data is something like this:
table one
1, A, ZZZ, 20.00, CAR
2, A, YYY, 80.00, CAR
3, B, YYY, 100.00, VAN
4, A, WWW, 100.00, BUS
table two
A, WWW
A, XXX
A, YYY
A, ZZZ
B, YYY
B, ZZZ
What I'm looking to end up with is the following data set
1, A, YYY, 80.00, CAR
2, A, ZZZ, 20.00, CAR
0, A, WWW, 0.00, CAR
0, A, XXX, 0.00, CAR
3, B, YYY, 100.00, VAN
0, B, ZZZ, 0.00, VAN
4, A, WWW, 100.00, BUS
0, A, XXX, 0.00, BUS
0, A, YYY, 0.00, BUS
0, A, ZZZ, 0.00, BUS
So, in other words I want all the data from table one PLUS any missing SubTypes from table two that match the Type of table one which would also include zero values for ID and Percentage, but keep the Category from the data set selected.
This works fine with an outer join if I only have one row in table one, but for each subsequent row my query adds more rows from table two. I think I need some sort of union or subquery that is aware of other rows selected from table one so will only select non-matching rows from table two.
Any help most appreciated!
Edit:
This is my current query (the more I think about this the more wrong it looks)
SELECT CASE WHEN t1.SubType = t2.SubType THEN t1.ID ELSE 0 END,
t1.Type, t2.SubType, CASE WHEN t1.SubType = t2.SubType THEN
t1.Percentage ELSE 0 END, t1.Category
FROM one t1
LEFT OUTER JOIN two t2
ON t2.Type = t1.Type
This gives me 8 rows - duplicated for each row selected from table one.
Another Edit:
Adding a couple more rows to table one I think explains this problem better. So the SQL to create tables and add rows looks like this:
create table one (ID int,Type nvarchar(1),SubType nvarchar(3),Percentage decimal(5,2),Category nvarchar(3))
create table two (Type nvarchar(1),SubType nvarchar(3))
insert into one values (1, 'A', 'ZZZ', 20.00, 'CAR')
insert into one values (2, 'A', 'YYY', 80.00, 'CAR')
insert into one values (3, 'B', 'YYY', 100.00, 'VAN')
insert into one values (4, 'A', 'WWW', 100.00, 'BUS')
insert into two values ('A', 'WWW')
insert into two values ('A', 'XXX')
insert into two values ('A', 'YYY')
insert into two values ('A', 'ZZZ')
insert into two values ('B', 'YYY')
insert into two values ('B', 'ZZZ')
I think this will do what you want:
SELECT ID, Type, SubType, Percentage, Category
FROM Table1
UNION ALL
SELECT 0, Type, SubType, 0.00, 'CAR'
FROM Table2 t2
LEFT JOIN t1 ON t1.Type = t2.Type AND t1.SubType = t2.SubType
WHERE t1.ID IS NULL
SELECT
ISNULL(t1.ID),
t2.Type,
t2.SubType,
ISNULL(t1.Percentage, 0),
ISNULL(t1.Category, 'CAR')
FROM Table2 t2
INNER JOIN (SELECT DISTINCT Type FROM Table1) f ON t2.Type = f.Type
LEFT JOIN Table1 t1 ON t2.Type = t1.Type AND t2.SubType = t1.SubType
You can do this without a UNION, just a LEFT JOIN:
UPDATED FOLLOWING COMMENT
SELECT ISNULL(t1.ID,0) Id, t2.Type, t2.SubType, ISNULL(t1.percentage,0) Percentage, ISNULL(t1.Category,'CAR') Category
FROM Table2 t2
LEFT JOIN Table1 t1
ON t1.Type = t2.Type AND t1.SubType = t2.SubType
WHERE t2.Type IN (SELECT DISTINCT Type FROM Table1)
Ok, this will give you the result you want, but its assigning the category as 'CAR', if you don't want that, then you should tell us what it should be.
Thanks for everyone's help on this, but I've worked it out myself finally...
SELECT ID, Type, SubType, Percentage, Category
FROM one
UNION
SELECT DISTINCT 0, t2.Type, t2.SubType, 0.00, t1.Category
FROM one t1
INNER JOIN two t2 ON t2.Type = t1.Type AND t2.SubType NOT IN
(SELECT t3.SubType FROM one t3 WHERE t3.Category = t1.Category and t3.Type = t1.Type)
ORDER BY Category, Type, SubType
I have two tables that have following rows:
Table1
ID Name Number
=====================
1 a 100
2 b 200
3 c 300
Table2
ID Number Check
=====================
1 100 0
2 200 1
3 300 null
Now I want the following table:
table
---------------------
Name Number check
=====================
a 100 0
c 300 null
What query I must to write.
*You notice that the column of check in the row of 'c' in final table is null.
Thanks.
Left outer join is your friend:
select table1.name, table1.nmber, table2.check from table1 left outer join table2 on table1.nmber = table2.number
Assuming that the nmber column in table1 = number column in table2
SELECT a.name, a.nmber, b.check
FROM table1 a JOIN table2 b ON a.nmber = b.number
I believe your looking for
select a.Name, a.Nmber, b.Check
from Table1 a join table2 b
on a.Nmber = b.Number
can also add a where clase e.g.
where a.Name is not b
where b.check is not 1
etc
Hard to tell from your question how you want your results to exclude b
Set up test data.
create table table1(ID int, Name char(1), Number int)
create table table2(ID int, Number int, [Check] int)
insert into table1 values (1, 'a', 100)
insert into table1 values (2, 'b', 200)
insert into table1 values (3, 'c', 300)
insert into table2 values (1, 100, 0)
insert into table2 values (2, 200, 1)
insert into table2 values (3, 300, null)
The query
select
table1.Name,
table1.Number,
table2.[Check]
from table1
inner join table2
on table1.ID = table2.ID
where Name <> 'b'
Result
a 100 0
c 300 NULL
You must use square brackets around column name [check] because check is a reserved word. in SQL Server.
This question has been edited a lot. I believe that the answer to the original question differ from the answer to the current question.
Here is the setup for version 1 one of the question.
create table table1(ID int, Name char(1), Number int)
create table table2(ID int, Number int, [Check] int)
insert into table1 values (1, 'a', 100)
insert into table1 values (2, 'b', 200)
insert into table1 values (3, 'c', 300)
insert into table2 values (1, 100, 0)
insert into table2 values (2, 200, 1)
To get c from table1 when joined to table2 you need to use a left outer join.
select
table1.Name,
table1.Number,
table2.[Check]
from table1
left outer join table2
on table1.ID = table2.ID
where table1.Name <> 'b'
Even in this version you need the square brackets around check.