How make sql query "not in" more simply use only "join"? - sql

Have query:
select a.id from selzde.elorder a
inner join selzde.elorder b on a.name = b.name
and a.workname = b.workname
and b.id = needId
where a.id not in (select id_elorder from selzde.drugselorder)
how make sql query not in more simply use only join?

select a.id from selzde.elorder a
inner join selzde.elorder b on a.name = b.name
and a.workname = b.workname
and b.id = needId
left outer join selzde.drugselorder d on a.id = d.id_elorder
where d.id_elorder is null

Left join to drugselorder, on id_elorder = a.id, then choose the ones with no match (i.e. where drugselorder is null)... I wouldn't say it was any more "simple", though.

One solution would be to use MINUS operator rather than not in as follows:
select a.id
from selzde.elorder a
inner join selzde.elorder b
on a.name = b.name
and a.workname = b.workname
and b.id = needId
MINUS
select id_elorder
from selzde.drugselorder
;
Hope this helps.
Regards,
Roger

Related

Case statement in JOIN slows the performance of the query

Case statement in JOIN slows the performance of the query, is there any way to improve to make the query performance faster
SELECT A.TestColumn
FROM A with(nolock)
INNER JOIN B with(nolock)
ON A.ID = B.ID
and A.InvoiceNo = CASE WHEN B.InvoiceType=2
THEN B.MainInvoiceNo
ELSE B.InvoiceNo END
Try :
1) with the valued CASE
SELECT A.TestColumn
FROM A
INNER JOIN B
ON A.ID = B.ID and
A.InvoiceNo = CASE B.InvoiceType
WHEN 2 THEN B.MainInvoiceNo
ELSE B.InvoiceNo
END
2) with a UNION ALL
SELECT A.TestColumn
FROM A
INNER JOIN B
ON A.ID = B.ID and
A.InvoiceNo = B.MainInvoiceNo
WHERE B.InvoiceType=2
UNION ALL
SELECT A.TestColumn
FROM A
INNER JOIN B
ON A.ID = B.ID and
A.InvoiceNo = B.InvoiceNo
WHERE B.InvoiceType<>2
probably using union will be the best performant :
SELECT A.TestColumn
FROM A
INNER JOIN B
ON A.ID = B.ID
and B.InvoiceType=2
and A.InvoiceNo = B.MainInvoiceNo
union all
SELECT A.TestColumn
FROM A with(nolock)
INNER JOIN B with(nolock)
ON A.ID = B.ID
and B.InvoiceType <> 2
and A.InvoiceNo = B.InvoiceNo
but also you can try using OR :
SELECT A.TestColumn
FROM A with(nolock)
INNER JOIN B with(nolock)
ON A.ID = B.ID
and
(
(B.InvoiceType= 2 and A.InvoiceNo = B.MainInvoiceNo)
or
(B.InvoiceType<> 2 and A.InvoiceNo = B.InvoiceNo)
)
I would suggest two LEFT JOINs and a WHERE
SELECT A.TestColumn
FROM A LEFT JOIN
B B1
ON A.ID = B1.ID AND
B1.InvoiceType = 2
A.InvoiceNo = B.MainInvoiceNo LEFT JOIN
B B2
ON A.ID = B2.ID AND
A.InvoiceNo = B2.InvoiceNo
WHERE B1.ID IS NOT NULL OR B2.ID IS NOT NULL;
SQL Server should find it much easier to implement an efficient execution plan. I would recommend indexes on B(ID, MainInvoiceNo, InvoiceType) and B(ID, InvoiceNo).
Using a case expression as part of the join criteria will be forcing SQL server to scan your index (probably a table scan if id is a clustered index).
Depending on the cardinality of your data and expected rows for each join condition, using two separate queries with the results unioned can yield better performance.
This is because for each individual query the optimiser can likely utilise an index seek resulting in far few logical reads overall.
Also since you are only returning data from A you could try using exists
Select A.TestColumn
from A
where exists (
select * from B where B.Id = A.Id and B.InvoiceType=2 and A.InvoiceNo=B.MainInvoiceNo
)
or exists (
select * from B where B.Id=A.Id and B.InvoiceNo = A.InvoiceNo
)

What is wrong with the following SQL left join?

I have 5 tables: A, B, C, D, E
A: {ID, Value, GroupID, FilterID, In_Date}
B: {ID, Description, Out_Date, From_Date }
C: {ID, Category}
D: {GroupID, GroupName}
E: {FilterID, FilterName}
There could be missing IDs in B and C as a result, I'm trying to do a LEFT JOIN to get the required info. In my dataset, I've explicitly added a row in A with ID that's not in B or C. I expect it to be picked up in the following query, but it doesn't happen. I believe I'm going wrong in the WHERE clause due to null values in B and C.
SELECT A.Value, A.Group, B.Description, C.Category, D.GroupName, E.FilterName
FROM A LEFT JOIN B ON A.ID = B.ID
LEFT JOIN C ON A.ID = C.ID,
D,E
WHERE
B.Out_Date>A.In_Date,
A.GroupID=D.GroupID,
A.FilterID=E.FilterID
How can I fix this to retrieve the fields I want with null values when the ID is not in B or C , but in A?
1) Don't mix old comma separated join syntax with modern explicit join syntax!
2) When left join, put the right side table's conditions in the ON clause to get true left join behavior. (When in WHERE you get inner join result.)
SELECT A.Value, A.Group, B.Description, C.Category, D.GroupName, E.FilterName
FROM A LEFT JOIN B ON A.ID = B.ID AND B.Out_Date > A.In_Date
LEFT JOIN C ON A.ID = C.ID
JOIN D ON A.GroupID = D.GroupID
JOIN E ON A.FilterID = E.FilterID
Value and Group are reserved words in ANSI SQL, so you may need to delimit them, as "Value" and "Group".
First point: You shouldn't mix join syntaxes, just use explicit syntax.
Because of your where clause, you effectively turn your left joins in inner joins. You are probably looking for:
SELECT A.Value, A.Group, B.Description, C.Category, D.GroupName, E.FilterName
FROM A
LEFT JOIN B
ON A.ID = B.ID
AND B.Out_Date > A.In_Date
LEFT JOIN C
ON A.ID = C.ID
INNER JOIN D
ON A.GroupID = D.GroupID
INNER JOIN E
ON A.FilterID = E.FilterID
You can use this query for your problem.
SELECT A.Value, A.Group, B.Description, C.Category, D.GroupName, E.FilterName
FROM A
LEFT JOIN B
ON A.ID = B.ID
AND B.Out_Date > A.In_Date
LEFT JOIN C
ON A.ID = C.ID
LEFT JOIN D
ON A.GroupID = D.GroupID
LEFT JOIN E
ON A.FilterID = E.FilterID
Here is your table details
A: {ID, Value, GroupID, FilterID, In_Date}
B: {ID, Description, Out_Date, From_Date }
C: {ID, Category}
D: {GroupID, GroupName}
E: {FilterID, FilterName}
now you try to retrieve data using left join
so you try the flowing script
SELECT A.Value, A.Group, B.Description, C.Category, D.GroupName,E.FilterName from A left join B on A.ID=B.ID
left Join C on A.ID=C.ID
Left Join D on A.GroupID=D.GroupID
Left Join E on A.FilterID=E.FilterID
where B.Out_Date>A.In_Date
I hope this is help full for you.

Join WHERE clause - table has row with defined value, or no entry

Can anyone help me figure out the correct WHERE clause for the following scenario:
select A.name
from tableA A, tableB B
where A.id = B.id
and
(
B.field = 5
OR
B.hasNoRowForJoinedID
)
I feel like I'm missing something really obvious here in how to accomplish this, but I can't for the life of me put my finger on it.
You are using an outdated SQL Syntax. To perform the LEFT OUTER JOIN based your your request above, you can do the following:
SELECT A.name
FROM A
LEFT OUTER JOIN B ON A.id = B.id
WHERE (B.field = 5 OR B.field IS NULL)
Use proper join syntax and not the outdated ones:
select A.name
from tableA A
left join tableB B on A.id = B.id and B.field = 5

SQL Select ISNULL not working

I used the query below to extract the data fro the table but it does not working.
SELECT A.ID, AVG(ISNULL(score,0)) AS sc FROM A
LEFT OUTER JOIN B ON A.ID = B.ID
WHERE A.aClass = '1st'
I wanted it to return all the data from Table A with its corresponding average score and return 0 if there is no score yet. Can anyone help me figure out the problem.
Try this
SELECT A.ID, AVG(ISNULL(B.score,0)) AS sc
FROM A
LEFT OUTER JOIN B ON A.ID = B.ID
WHERE A.aClass = '1st'
GROUP BY A.ID

Simulate a left join without using "left join"

I need to simulate the left join effect without using the "left join" key.
I have two tables, A and B, both with id and name columns. I would like to select all the dbids on both tables, where the name in A equals the name in B.
I use this to make a synchronization, so at the beginning B is empty (so I will have couples with id from A with a value and id from B is null). Later I will have a mix of couples with value - value and value - null.
Normally it would be:
SELECT A.id, B.id
FROM A left join B
ON A.name = B.name
The problem is that I can't use the left join and wanted to know if/how it is possible to do the same thing.
you can use this approach, but you must be sure that the inner select only returns one row.
SELECT A.id,
(select B.id from B where A.name = B.name) as B_ID
FROM A
Just reverse the tables and use a right join instead.
SELECT A.id,
B.id
FROM B
RIGHT JOIN A
ON A.name = B.name
I'm not familiar with java/jpa. Using pure SQL, here's one approach:
SELECT A.id AS A_id, B.id AS B_id
FROM A INNER JOIN B
ON A.name = B.name
UNION
SELECT id AS A_id, NULL AS B_id
FROM A
WHERE name NOT IN ( SELECT name FROM B );
In SQL Server, for example, You can use the *= operator to make a left join:
select A.id, B.id
from A, B
where A.name *= B.name
Other databases might have a slightly different syntax, if such an operator exists at all.
This is the old syntax, used before the join keyword was introduced. You should of course use the join keyword instead if possible. The old syntax might not even work in newer versions of the database.
I can only think of two ways that haven't been given so far. My last three ideas have already been given (boohoo) but I put them here for posterity. I DID think of them without cheating. :-p
Calculate whether B has a match, then provide an extra UNIONed row for the B set to supply the NULL when there is no match.
SELECT A.Id, A.Something, B.Id, B.Whatever, B.SomethingElse
FROM
(
SELECT
A.*,
CASE
WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN 1
ELSE 0
END Which
FROM A
) A
INNER JOIN (
SELECT 1 Which, B.* FROM B
UNION ALL SELECT 0, B* FROM B WHERE 1 = 0
) B ON A.Which = B.Which
AND (
A.Which = 0
OR (
A.Which = 1
AND A.Id = b.Id
)
)
A slightly different take on that same query:
SELECT A.Id, B.Id
FROM
(
SELECT
A.*,
CASE
WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN A.Id
ELSE -1 // a value that does not exist in B
END PseudoId
FROM A
) A
INNER JOIN (
SELECT B.Id PseudoId, B.Id FROM B
UNION ALL SELECT -1, NULL
) B ON A.Which = B.Which
AND A.PseudoId = B.PseudoId
Only for SQL Server specifically. I know, it's really a left join, but it doesn't SAY LEFT in there!
SELECT A.Id, B.Id
FROM
A
OUTER APPLY (
SELECT *
FROM B
WHERE A.Id = B.Id
) B
Get the inner join then UNION the outer join:
SELECT A.Id, B.Id
FROM
A
INNER JOIN B ON A.name = B.name
UNION ALL
SELECT A.Id, NULL
FROM A
WHERE NOT EXISTS (
SELECT *
FROM B
WHERE A.Id = B.Id
)
Use RIGHT JOIN. That's not a LEFT JOIN!
SELECT A.Id, B.Id
FROM
B
RIGHT JOIN A ON B.name = A.name
Just select the B value in a subquery expression (let's hope there's only one B per A). Multiple columns from B can be their own expressions (YUCKO!):
SELECT A.Id, (SELECT TOP 1 B.Id FROM B WHERE A.Id = B.Id) Bid
FROM A
Anyone using Oracle may need some FROM DUAL clauses in any SELECTs that have no FROM.
You could use subqueries, something like:
select a.id
, nvl((select b.id from b where b.name = a.name), "") as bId
from a
you can use oracle + operator for left join :-
SELECT A.id, B.id
FROM A , B
ON A.name = B.name (+)
Find link :-
Oracle "(+)" Operator
SELECT A.id, B.id
FROM A full outer join B
ON A.name = B.name
where A.name is not null
I'm not sure if you just can't use a LEFT JOIN or if you're restricted from using any JOINS at all. But as far as I understand your requirements, an INNER JOIN should work:
SELECT A.id, B.id
FROM A
INNER JOIN B ON A.name = B.name
Simulating left join using pure simple sql:
SELECT A.name
FROM A
where (select count(B.name) from B where A.id = B.id)<1;
In left join there are no lines in B referring A so 0 names in B will refer to the lines in A that dont have a match
+ or A.id = B.id in where clause to simulate the inner join