SQL - alternative to left outer join - sql

There is a standard way in SQL to conut a number of rows joined to one table acepting also the 0?
That is one example :
SELECT t1.id, COUNT(t2.*)
FROM t1 LEFT OUTER JOIN t2 ON ( t1.id = t2.id )
GROUP BY t1.id
I need a alternative because i use odbc with different databases, and on some databases the left join aren't supported.

SELECT
t1.id,
(SELECT COUNT(*) FROM t2 WHERE t2.id = t1.id) as t2_count
FROM t1

Two Options:
Option 1: use the (+) operator:
SELECT t1.id, COUNT(t2.*)
FROM t1, t2
WHERE t2.id(+) = t1.id
GROUP BY t1.id
I don;t know if it works on all drivers. Option 2 that will work with all drivers is to create a view and create the view instead.

Related

Is it possible to share the same filter parameters (WHERE CLAUSE) with two more fields in SQL?

Consider below
SELECT * FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
WHERE
t1.A NOT IN ('111111','222222','33333')
AND
t2.B NOT IN ('111111','222222','33333')
Is there another way to use the same filter parameters for two different fields?
Something like that
SELECT * FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
WHERE (t1.A and t2.B) NOT IN ('111111','222222','33333')
Seems pretty simple, but I couldn't find anything in the docs.
You could use the array intersection operator (&&) to simulate that condition - create an array of the columns and an array of the values to test, and have a where clause that checks there's no intersection between them:
SELECT *
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
WHERE NOT ARRAY[t1.A, t2.B] && ARRAY['111111', '222222', '33333']
A CTE would be one possibility.
WITH cte
AS
(
SELECT c
FROM (VALUES ('111111'),
('222222'),
('33333')) v
(c)
)
SELECT *
FROM table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.id
WHERE t1.a NOT IN (SELECT c
FROM cte)
AND t2.c NOT IN (SELECT c
FROM cte);

Seeking suggestion about Left join

I have two tables t1 & t2. In t1, there are 1641787 records. In t2, there are 33176007 records. I want to take two columns from table2 and keep everything of t1. When I use left join with t1 to t2, I got more records than t1. I would like to get a similar number of records as t1 after joining. Please give me a suggestion. Here is my code:
SELECT t1.*,
t2.City
FROM t1
LEFT JOIN
t2
ON t1.ID = t2.ID;
You can aggregate and choose an arbitrary value:
select t1.*, t2.city
from t1 left join
(select t2.id, any_value(t2.city) as city
from t2
group by t2.id
) t2
on t1.id = t2.id;

Joining selected column to a table

I am try running this query and it takes long time because of the join i am using
SELECT T1.Id,T2.T2Id,T2.Col2
FROM Table1 T1
LEFT OUTER JOIN (SELECT TOP 1 Id, TT.T2Id,TT.Col2
FROM Table2 TT
WHERE TT.TypeId=3
ORDER BY TT.OrderId
)AS T2 ON T2 .Id=T1.Id
Thing is it doesn't let me do something like TT.Id=T1.Id with in the join query.
Is there any other way I can do this?
Try it with outer apply:
SELECT T1.Id, T2.T2Id, T2.Col2
FROM Table1 T1
OUTER APPLY (SELECT TOP 1 T2Id, T2.Col2
FROM Table2 TT
WHERE TT.TypeId = 3 AND TT.Id = T1.Id) T2
SELECT T1.Id, T2.T2Id, T2.Col2
FROM Table1 T1
OUTER APPLY (SELECT TOP 1 T2Id, T2.Col2
FROM Table2 TT
WHERE TT.TypeId = 3 AND T1.Id = TT.Id
Order by T2id desc) T2
I would use Outer Apply and T1.Id = TT.Id in the where condition since T1 is the parent table plus adding on order by - if needed for ordered result set
Well first of all your derived table will produce non deterministic results, as the top 1 row you return may differ each time you run it, even if the data in the table remains the same. You could put an order by clause in the the derived table to prevent that.
Is there an index on Table1.id? What exactly are you trying to achieve though, is it to return all rows from Table1, with just one row of many from Table2 that has the same ID?
If so I would look into using Cross Apply instead. Or maybe in this case Outer Apply. If I get a chance later I'll write up an example if needed, but in the mean time just Google Outer Apply for SQL Server.
Dan

Join query where table references itself

I'm using Oracle 10, but the best way to ask this question is with an example.
select *
from t1, t2
where t1.id = t2.id
and t1.otherID = (select max(otherID)
from t2
where id = THE ID FROM THE OUTER QUERY T1
)
I think you see where I'm trying to go with this. I need to reference t1 in the subquery to join it to the max of t2.
I need to know how to create a query like this.
"THE ID FROM THE OUTER QUERY T1" is where my confusion is.
I tried using t1.id, but did not get results.
Try the following
select t1.*, t2.*
from t1
join t2 on t1.id = t2.id
join (select id, max(otherID) as max_otherID
from t2
group by id
) a ON a.id = t1.id and a.max_otherID = t1.otherID
Using a sub-query on the join often gives better performance than using it in the where clause.

SQL Joining three tables and using LEFT OUTER JOIN

I have three tables and two seperate SQL queries which are working correctly and I am having correct results.
If I try to join these three tables I am having null as result.
First query:
select T1.ID,T3.COMPANY
from T1,T3
where (T1.status!='CLOSED') and (T1.PRIORITY)>5 and T1.CLASSID=T3.CLASSID
Second query:
SELECT T1.ID, T2.DESCRIPTION
FROM T1
LEFT OUTER JOIN T2
ON T1.ID=T2.KEY
WHERE T1.status!='CLOSED'
AND (T2.CREATEDATE= (SELECT MAX(CREATEDATE)
FROM T2
WHERE T2.KEY=T1.ID))
I tried to join them but as result I am having null:
select T1.ID,T3.COMPANY,T2.DESCRIPTION
from T1
INNER JOIN T3 ON T1.CLASSID=T3.CLASSID
LEFT OUTER JOIN T2
ON T1.ID=T2.KEY
where (T1.status!='CLOSED') AND (T1.PRIORITY)>5
AND (T2.CREATEDATE= (SELECT MAX(CREATEDATE)
FROM T2
WHERE T2.KEY=T1.ID))
like it does not recognized last part for taking MAX value from T2 table.
What am I doing wrong? Thanks for help
Firstly, use an alias for the subquery on table T2.
T2.CREATEDATE =
(SELECT MAX(T2Alias.CREATEDATE)
FROM T2 AS T2Alias
WHERE T2Alias.KEY = T1.ID)
Secondly, consider moving this condition into the ON clause of the LEFT JOIN to table T2.
The first thing that jumps out at me is the new dependency on both T1.Priority > 5 and T2.CreateDate value being equal to the result of the inline query:
( AND (T1.PRIORITY) > 5
AND (T2.CREATEDATE =
(SELECT MAX(CREATEDATE) FROM T2 WHERE T2.KEY = T1.ID) )
Without the data it's difficult to check however this may be the issue