SQL Server - Convert all subqueries to joins - sql-server

I have below query which has multiple nested subqueries.
The requirement is to convert all the nested subqueries into joins with main outer select query.
select * from t1
where not exists (
select 1 from t2
join t21 on t21.c = t2.c
where t2.y = t1.y
and t2.x in (
select top 1 x from t3
join t31 on t31.d = t3.d
where t3.z = t2.z
and t3.a = t1.a
order by t3.b
)
)
Can anyone please help me achieve this?

Related

Sum on subqueries on EF Core Linq

I want to get a result by typing subquery into the sum query.
The following code works when I write to Sql.
But on EF, how do I add another select at the top?
SQL
This code is work.
select
sum (data.rate)
from
(
SELECT
t1.Id,
(c.rate /
(SELECT COUNT(1) FROM [table4] AS [t4] WHERE ([t4].[FKId] = p1.Id))) as rate
FROM [table1] AS [t1]
INNER JOIN [table2] AS [t2] ON ([t1].[FKId] = [t2].[Id])
INNER JOIN [table3] AS [t3] ON ([t1].[FKId] = [t3].[Id]))
as data
C#
var data = await (
????
from t1 in ctx.table1
join t2 in ctx.table2 on new { t1.FKId} equals new { FKId = t2.Id}
join t3 in ctx.table3 on new { t1.FKId} equals new { FKId = t3.Id}
select new
{
rate = t3.Rate /
(from t4 in ctx.table4
where t4.FKId == t2.Id
select t4.Id)
.Count())
})
.SumAsync(sm => (double?)sm.rate ?? 0);
This c# code is not working.
Error:
Cannot perform an aggregate function on an expression containing an
aggregate or a subquery.
Per this answer, EF Core 3.0 still can't handle this situation (!).
However, you can translate the query without a subquery (effectively, using SelectMany) and it should work:
var ans = await (from t1 in ctx.table1
join t2 in ctx.table2 on t1.FKId equals t2.Id
join t3 in ctx.table3 on t1.FKId equals t3.Id
from t4 in ctx.table4
where t4.FkId == t2.Id
group t4.Id by new { t3.rate, t2.Id } into t2g
select t2g.Key.rate / t2g.Count()
)
.SumAsync();

Why these queries returns different results?

Both of these sql server queries should return the same count result, but returns different - 8219 and 7876.
Left join should return all rows from left table (8219).
What could be the reason of such result (7876)?
select count(*)
from t1 left join t2 on t1.id=t2.id
where t2.[date]='20191001'
-- returns 7876
select count(*)
from t1 left join t2 on t1.id=t2.id
-- returns 8219
select count(*)
from t2
where [date]<>'20191001' or [date] is null
-- returns 0
Your first query has a LEFT JOIN, but the WHERE clause is turning it into an inner join, because it filters out all NULL values.
The correct solution is to move the condition to the ON clause:
select count(*)
from t1 left join
t2
on t1.id = t2.id and t2.[date] = '20191001';

How to do search on a table while table have millions of record

I have to run this below query in sybase database and this will return millions of record.
but when i run it took lot of time and many of times timeout.
select * from table1 t1
where t1.oneid IN
(
select t2.oneid
from table2 t2
where t2.twoid IN
(
select DISTINCT t3.twoid from table3 t3
)
)
at isolation 0
so can any one suggest me a way so i can do some bulk operation for getting data?
Try this :
SELECT
t1.*
FROM (
SELECT
DISTINCT t3.twoid
FROM table3 t3
) as tmp
INNER JOIN table2 t2
ON t2.twoid = tmp.twoid
INNER JOIN table1 t1
ON t1.oneid = t2.oneid
It should be faster especially if you have indexes on t2.twoid and t1.oneid

How do I make this Access sql statement work with Sql Server?

I have almost finished replacing our applications back end with Sql Server but am coming up against an issue. The following Access query is not working with Sql Server.
SELECT table1.*
FROM table1
INNER JOIN (table2
INNER JOIN table3
ON ( table2.custkey = table3.custkey )
AND ( table2.sequence = table3.sequence ))
ON table1.account = table2.account
WHERE (( LEFT(table2.keyid, 1) = 'B' ))
ORDER BY table3.lastname & table3.firstname,
table1.account;
I have tried multiple variations of this statement but have not been able to get it to work. Some help with this statement will help me modify a few others. Any help would be appreciated.
The only thing that sticks out is "&" which is + in SQL Server. However, & in access also treats NULL values as the empty string, which needs further processing with ISNULL in SQL Server:
SELECT table1.*
FROM table1
INNER JOIN (table2
INNER JOIN table3
ON ( table2.custkey = table3.custkey )
AND ( table2.sequence = table3.sequence ))
ON table1.account = table2.account
WHERE (( LEFT(table2.keyid, 1) = 'B' ))
ORDER BY isnull(table3.lastname,'') + isnull(table3.firstname,''),
table1.account;
If I were to write the query in SQL Server from scratch, I would probably do the joins serially rather than do the t2-t3 in a bracket before joining back to t1. The test for the first character would also be expressed as LIKE (a personal preference).
SELECT table1.*
FROM table1
JOIN table2 ON table1.account = table2.account
JOIN table3 ON table2.custkey = table3.custkey AND table2.sequence = table3.sequence
WHERE table2.keyid LIKE 'B%'
ORDER BY isnull(table3.lastname,'') + isnull(table3.firstname,''), table1.account;
SELECT table1.*
FROM table1
INNER JOIN table2 ON table1.account = table2.account
INNER JOIN table3 ON ( table2.custkey = table3.custkey )
AND ( table2.sequence = table3.sequence )
WHERE LEFT(table2.keyid, 1) = 'B'
ORDER BY table3.lastname, table3.firstname, table1.account;
If you want the where clause to be suitable for an index, rewrite using LIKE:
SELECT table1.*
FROM table1
INNER JOIN table2 ON table1.account = table2.account
INNER JOIN table3 ON ( table2.custkey = table3.custkey )
AND ( table2.sequence = table3.sequence )
WHERE table2.keyid LIKE 'B%'
ORDER BY table3.lastname, table3.firstname, table1.account;

Can I use a column calculated in a SQL Server view later on in that same view?

Can I use a column calculated in a SQL Server view later on in that same view?
Let's say I have the following view:
Select
t1.StartMile, t2.EndMile, t2.EndMile- t1.StartMile as TotMile
from
TableStarts as t1
inner join
TableEnds as t2 on t1.Id = t2.Id
Is there a way to edit the view to do the following
Select
t1.StartMile, t2.EndMile, t2.EndMile - t1.StartMile as TotMile,
TotMile + 30 as EvenMoreMiles
I tried this and got error:
Invalid column name 'TotMile'
Please don't tell me to use t2.EndMile - t1.StartMile + 30 as EvenMoreMiles. TotMiles is a long case statement in my actual code.
I rather not have to create an intermediate view.
I am using SQL Server 2005.
ADDED LATER
Thanks for all the answers. I will upvote all.
The answers raise the following new question:
Given that there are thousands of rows, and TotMiles looks like the following, which of the answers given would be the most efficient? Or would it be most efficient to create an intermediary view?
CASE WHEN t .TaskType = 1 and t .StartTime < '1/1/2012'
THEN (tv.EndMile - tv.StartMile )
WHEN NOT (t .Location1_PKey = c.pkey OR t .Location2_PKey = c.pkey)
then (tv.EndMile - tv.StartMile )
WHEN (tv.EndMile - tv.StartMile ) < 31 Then 0
ELSE (tv.EndMile - tv.StartMile - 30 )
END AS MilesAdjusted2012,
You can also use CROSS APPLY which can be more concise, particularly if you are building up chains of aliases that reference preceding ones.
SELECT t1.StartMile,
t2.EndMile,
TotMile,
EvenMoreMiles,
AndYetMoreMiles
FROM TableStarts AS t1
INNER JOIN TableEnds AS t2
ON t1.Id = t2.Id
CROSS APPLY (SELECT t2.EndMile - t1.StartMile) A(TotMile)
CROSS APPLY (SELECT TotMile + 30) A2(EvenMoreMiles)
CROSS APPLY (SELECT EvenMoreMiles + 100) A3(AndYetMoreMiles)
You can't directly, but you can build up sub-selects:
select StartMile,EndMile,TotMile,TotMile+30 as EvenMoreMiles from (
Select t1.StartMile, t2.EndMile, t2.EndMile- t1.StartMile as TotMile
from
TableStarts as t1
inner join
TableEnds as t2
on t1.Id = t2.Id
) t
Or use Common Table Expressions:
;with FirstCalcs as (
Select t1.StartMile, t2.EndMile, t2.EndMile- t1.StartMile as TotMile
from
TableStarts as t1
inner join
TableEnds as t2
on t1.Id = t2.Id
)
select StartMile,EndMile,TotMile,TotMile+30 as EvenMoreMiles from FirstCalcs
I'd generally prefer to use CTEs if there's going to be a number of levels that build up the final calculations, because otherwise most formatting schemes struggle to make select, sub-select, sub-sub-select, etc, easy to read. CTEs can include references to previously defined CTEs:
;with CTE1 as (
SELECT ...
), CTE2 as (
SELECT ... FROM CTE1
), CTE3 as (
SELECT ... FROM CTE2
), CTE4 as (
SELECT ... FROM CTE2 ... CTE3
)
SELECT ... FROM CTE4 ... CTE1
Try using a Derived Table.
SELECT
DerivedTable.*,
TotMile + 30 as EvenMoreMiles
From (Select
t1.StartMile,
t2.EndMile,
t2.EndMile- t1.StartMile as TotMile
FROM Table t1
Inner Join table2 t2 on t1.PK = t2.FK) DerivedTable
You can do this using a Common Table Expression (CTE). Lots on that here: https://web.archive.org/web/20210927200924/http://www.4guysfromrolla.com/webtech/071906-1.shtml
Basically,
CREATE VIEW ... AS
WITH Mileage (StartMile, EndMile, TotMile) AS (Select t1.StartMile, t2.EndMile, t2.EndMile- t1.StartMile as TotMile
from
TableStarts as t1
inner join
TableEnds as t2
on t1.Id = t2.Id)
SELECT TotMile FROM Mileage

Resources