I have SQL code that is run on SQL Server 2017 in less than 200 ms, but the same code on SQL Server 2012 takes more than 3 seconds - can anyone tell me:
why is this happening
how do I solve it
select count(*) from dbo.mConsultationQuestionsReplies = 1,300,000
This is my code:
DECLARE #maxCount int;
DECLARE #ddlIds nvarchar(max);
SET #maxCount = 6;
SET #ddlIds = '4,8,840,779,10,813,3,18,7,918';
IF OBJECT_ID('tempdb..#rList') IS NOT NULL
DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL
DROP TABLE #docList
SELECT
rd.UserID,
(CASE
WHEN ids1.value IS NULL
THEN CAST(ids2.value AS int)
ELSE CAST(ids1.value AS int)
END) [cid]
INTO
#docList
FROM
mDJDoctors [rd]
LEFT JOIN
dbo.[mDJDoctorsSpeciality] [rs] ON rd.DoctorID = rs.doctorId
LEFT JOIN
dbo.mDJSpecialtyCategory [rca] ON rca.SpecialtyId = rs.specialId
LEFT JOIN
STRING_SPLIT(#ddlIds, ',') [ids1] ON rca.CategoryId = ids1.value
LEFT JOIN
dbo.mDJDoctorsSpecialtyAbove [ars] ON ars.doctorId = rd.DoctorID
LEFT JOIN
dbo.mDJSpecialtyAboveCategory [arca] ON arca.AboveSpecialtyId = ars.SpecialtyAboveId
LEFT JOIN
STRING_SPLIT(#ddlIds, ',') [ids2] ON [arca].CategoryId = ids2.value
WHERE
[ids1].value IS NOT NULL
OR [ids2].value IS NOT NULL
SELECT *
INTO #rList
FROM
(SELECT
*,
ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber
FROM
(SELECT DISTINCT r.ReplyUserID, r.ReplyDateInsert, d.cid
FROM dbo.mConsultationQuestionsReplies[r]
JOIN #docList [d] ON r.ReplyUserID = d.UserID
WHERE r.ReplyId IN (SELECT MAX(r.ReplyId)[id]
FROM dbo.mConsultationQuestionsReplies[r]
JOIN #docList [d] on r.ReplyUserID = d.UserID
GROUP BY d.cid, d.UserID)) [t]) [t]
WHERE
t.rowNumber <= #maxCount
SELECT
u.FirstName AS DoctorName,
u.UserID AS DoctorUserId,
sp.specialFaName AS DoctorSpecialty,
ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
md.DoctorGUID,
md.DoctorID,
cp.ProfileISOnline,
p.ProfilePicture AS DoctorProfilePicture,
p.ProfileDateInserted,
r.ReplyDateInsert AS LastReplyDateInsert,
r.cid
FROM
dbo.mDJDoctors AS md
INNER JOIN
dbo.Core_Users AS u ON md.UserID = u.UserID
INNER JOIN
dbo.Core_Profiles AS p ON u.UserID = p.UserID
INNER JOIN
(SELECT * FROM #rList) [r] ON r.ReplyUserID = u.UserID
INNER JOIN
dbo.mConsultationDocterProfile AS cp ON cp.UserID = u.UserID
LEFT OUTER JOIN
dbo.mDJDoctorsSpeciality AS mdad ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN
dbo.mDJSpecialty AS sp ON mdad.specialId = sp.specialId
LEFT OUTER JOIN
dbo.mDJDoctorsSpecialtyAbove AS mdad2 ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN
dbo.mDJSpecialtyAbove AS ab ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE
cp.ProfileISOnline = 1
update :
base on guid from marc-s , i removed STRING_SPLIT and new result is
declare #maxCount int;
set #maxCount = 6;
IF OBJECT_ID('tempdb..#rList') IS NOT NULL DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL DROP TABLE #docList
select rd.UserID, (case when arca.CategoryId is null then cast(rca.CategoryId as int) else cast(arca.CategoryId as int) end)[cid] into #docList
from mDJDoctors [rd] WITH (NOLOCK)
left join dbo.[mDJDoctorsSpeciality] [rs] WITH (NOLOCK) on rd.DoctorID = rs.doctorId
left join dbo.mDJSpecialtyCategory [rca] WITH (NOLOCK) on rca.SpecialtyId = rs.specialId
left join dbo.mDJDoctorsSpecialtyAbove [ars] WITH (NOLOCK) on ars.doctorId = rd.DoctorID
left join dbo.mDJSpecialtyAboveCategory [arca] WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId
where arca.CategoryId in (4,8,840,779,10,813,3,18,7,918) or rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
select * into #rList from (
select * , ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber from (
select distinct r.ReplyUserID, r.ReplyDateInsert, d.cid
from dbo.mConsultationQuestionsReplies[r] WITH (NOLOCK)
join #docList [d] on r.ReplyUserID = d.UserID
where r.ReplyId in(
select max(r.ReplyId)[id]
from dbo.mConsultationQuestionsReplies[r] WITH (NOLOCK)
join #docList [d] on r.ReplyUserID = d.UserID
group by d.cid,d.UserID
))[t])[t] where t.rowNumber <= #maxCount
SELECT distinct
u.FirstName AS DoctorName,
u.UserID AS DoctorUserId,
sp.specialFaName AS DoctorSpecialty,
ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
md.DoctorGUID,
md.DoctorID,
cp.ProfileISOnline,
p.ProfilePicture AS DoctorProfilePicture,
p.ProfileDateInserted,
r.ReplyDateInsert AS LastReplyDateInsert,
r.cid
FROM dbo.mDJDoctors AS md WITH (NOLOCK)
INNER JOIN dbo.Core_Users AS u WITH (NOLOCK)
ON md.UserID = u.UserID
INNER JOIN dbo.Core_Profiles AS p WITH (NOLOCK)
ON u.UserID = p.UserID
INNER JOIN
(
select * from #rList
) [r]
ON r.ReplyUserID = u.UserID
INNER JOIN dbo.mConsultationDocterProfile AS cp WITH (NOLOCK)
ON cp.UserID = u.UserID
LEFT OUTER JOIN dbo.mDJDoctorsSpeciality AS mdad WITH (NOLOCK)
ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN dbo.mDJSpecialty AS sp WITH (NOLOCK)
ON mdad.specialId = sp.specialId
LEFT OUTER JOIN dbo.mDJDoctorsSpecialtyAbove AS mdad2 WITH (NOLOCK)
ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN dbo.mDJSpecialtyAbove AS ab WITH (NOLOCK)
ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE cp.ProfileISOnline = 1
order by cid, LastReplyDateInsert
its take 200 ms in sql 2017 and take 1038ms in sql 2012
update 3:
this i my execution plans xml for 2012 and 2017
2012 and 2017 execution plans
update 4:
server config
The SQL Server 2012 database is missing an index (compared to SQL Server 2017) on [dbo].[Core_Profiles]
For SQL Server 2012, there is no index on [dbo].[Core_Profiles].Userid and although the query has only 52 distinct userids, it scans the full [Core_Profiles] table (~0.5mil rows) to hash match it with 52 rows and return: 52 rows (the scale diff is considerable).
For SQL Server 2017, there is the [missing_index_9245_9243] (which also includes the ProfilePicture{?}). Instead of half million table scan, it performs a 52 rows/times loops join. There is still a keylookup to [Core_Profiles] for the retrieval of ProfileDateInserted.
The first thing to try, would be to create an index on [dbo].[Core_Profiles].Userid. Whether you choose to include the ProfilePicture is a bit irrelevant to the particular query since a key lookup is performed anyway.
A side suggestion would be to create indexes on the #temp tables. Also the retrieval of the mDJDoctorsSpeciality & mDJDoctorsSpecialtyAbove (the set of 4 table outer-joins) is used twice in the batch. Wouldn't the first execution satisfy the second(returned resultset?), so why not store it and use the #temp table instead of querying the tables again (caveat: have not looked at the query logic/model at all, only at the plans) . Most likely, the queries could be nested (inner joins), something like:
from mDJDoctors [rd] WITH (NOLOCK)
left join
(
dbo.[mDJDoctorsSpeciality] [rs] WITH (NOLOCK)
join dbo.mDJSpecialtyCategory [rca] WITH (NOLOCK) on rca.SpecialtyId = rs.specialId and rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on rd.DoctorID = rs.doctorId
left join
(
dbo.mDJDoctorsSpecialtyAbove [ars] WITH (NOLOCK)
join dbo.mDJSpecialtyAboveCategory [arca] WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId and arca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on ars.doctorId = rd.DoctorID
where rs.doctorId is not null or rd.DoctorID is not null
on a second thought, isn't this a union?
(
DoctorId from dbo.mDJSpecialtyCategory....
union
DoctorId from dbo.mDJSpecialtyAboveCategory....
) as X
join mDJDoctors [rd] on DoctorId....
If I would be in your situation I would first look at the differences between the 2 instances; there are a lot of things that can impact performance of a query, just looking at the code is not enough in your case (running the same query on 2 separate instances).
So, take a look at the memory allocated to each instance, the settings (MAXDOP and CTP are a good start), are they running on the same machine? If not, are there any significant HW differences? Is there more usage (other people or applications running queries) of your SQL Server 2017 than your SQL Server 2012? Do you have the same amount of data on both servers? Are your indexes the same and are they maintained on both instances (could it be that you have a high level of fragmentation on your SQL Server 2017)? Also, take a look at the execution plans to see if they are identical on both servers.
I know it seems like a lot of questions, but without knowing the full context is hard to answer; any of the above could be the culprit for the slowness.
Related
I have this query and it's returning the results I expect, however, as you can see it's really crude & difficult to read.
I tried Inner Joins and FIRST_VALUE approaches but wasn't getting the right results so resorted to temp tables (just because I find it easier to verify results that way).
The issue is I get a StartWayPoint and EndWayPoint from dbo.Trips which is actually just the first and last points entered into the GPSWaypoints table (for a particular trip / vehicle).
Those points aren't entered in UTCTime order so I need to take the StartWayPoint, EndWayPoint & Vehicle, get results BETWEEN those waypoint values from dbo.GPSWaypoints table, sort that by UTCTime desc and the first Location string there is my true EndLocationString.
Hope that makes sense, I may have over complicated it ....I feel as though the answer is either an Inner Join or a SubQuery, my SQL skills aren't that hot though so any help appreciated.
DROP TABLE IF EXISTS #temp1, #temp2
USE XXX
DECLARE #StartWayPoint bigint, #EndWaypoint bigint, #Vehicle smallint, #TripId smallint = 9863;
SELECT t.Id,
t.Date,
t.StartWayPoint,
t.EndWayPoint,
t.Distance,
t.Alarms,
t.FuelConsumption,
t.Vehicle,
gpsStart.UtcTime as TripStart,
gpsEnd.UtcTime as TripEnd,
gpsStart.LocationString as StartLocationString,
gpsEnd.LocationString as EndLocationString
INTO #temp1
FROM dbo.Trips t
LEFT JOIN dbo.GPSWaypoints gpsStart on StartWaypoint = gpsStart.Id
LEFT JOIN dbo.GPSWaypoints gpsEnd on EndWaypoint = gpsEnd.Id
LEFT JOIN dbo.Operators o on Driver = o.Id
LEFT JOIN dbo.Vehicles v on t.Vehicle = v.Id
WHERE t.id = #TripId
SELECT #StartWayPoint = (SELECT StartWaypoint FROM #temp1), #EndWaypoint = (SELECT EndWaypoint FROM #temp1), #Vehicle = (SELECT Vehicle FROM #temp1)
SELECT TOP 1 g.Id,
g.LocationString,
g.Vehicle
INTO #temp2
FROM dbo.GPSWaypoints g
WHERE Id BETWEEN #StartWayPoint AND #EndWaypoint
AND Vehicle = #Vehicle
order by UtcTime desc
SELECT t1.*,
t2.Id as TRUE_EndWayPoint,
t2.LocationString as TRUE_EndLocationString
FROM #temp1 t1
LEFT JOIN #temp2 t2 on t2.Vehicle = t1.
Results from #temp1
Results from #temp2 (with TRUE EndWayPoint and EndLocationString
Think I've answered it for myself with a nested query, must have just had an error in my earlier attempts ....still open to suggestions for improvement though.
select t.Id,
t.Date,
t.StartWayPoint,
t.EndWayPoint,
t.Distance,
t.Alarms,
t.FuelConsumption,
t.Vehicle,
gpsStart.UtcTime as TripStart,
gpsEnd.UtcTime as TripEnd,
gpsStart.LocationString as StartLocationString,
( select top 1 (g.LocationString)
from dbo.GPSWaypoints g
where Id BETWEEN gpsStart.Id AND gpsEnd.Id
AND Vehicle = v.Id
order by UtcTime desc
) as EndLocationString
from dbo.Trips t
left join dbo.GPSWaypoints gpsStart on StartWaypoint = gpsStart.Id
left join dbo.GPSWaypoints gpsEnd on EndWaypoint = gpsEnd.Id
left join dbo.Operators o on Driver = o.Id
left join dbo.Vehicles v on t.Vehicle = v.Id
where t.id = 9863
I have a problem with my query. I have to do left outer join only if condition is true. If condition is false do another left outer join.
I tried with this but not successfully:
select
*
from
works with(nolock)
if work.type = 1
begin
left outer join
users with(nolock) on users.id = work.owner
else
left outer join
groups with(nolock) on groups.id = work.owner
end
How can I solve this problem?
you should try left join both of them, but inside of the select, take what you want depending on the use case.
SELECT
*,
CASE work.type WHEN '1' THEN 'a.owner' ELSE 'b.owner' END AS owner
FROM
blahblah
left join users on blahblah.user_id = users.id as a,
left join groups as blahblah.groups_id = groups.id as b
You can try below query.
First method:
select
works.*, isnull(users.id, groups.id)
from
works with(nolock)
left outer join
users with(nolock) on users.id = works.owner and work.type = 1
left outer join
groups with(nolock) on groups.id = works.owner
Second method:
if exists (select 1 from works with (nolock) where works.type = 1)
select *
from works with(nolock)
left outer join users with(nolock) on users.id = works.owner
else
select *
from works with(nolock)
left outer join groups with(nolock) on groups.id = works.owner
third method: use dynamic SQL to build query at runtime.
Considering that you want to display all columns (*), then you can conditionally join against both tables by checking the work.type as a join condition:
select
*
from
works
left join users on
users.id = work.owner and
work.type = 1
left join groups on
groups.id = work.owner and
(work.type <> 1 OR work.type IS NULL)
A particular row from the works table can only have a particular value for type, so it will join against users or against groups, but never both. The problem with this solution becomes the displayed columns, since we are joining against both tables, now you have to unify groups and users columns.
You can do this with a bunch of ISNULLs:
select
works.*,
Column1 = ISNULL(users.Column1, groups.Column1),
Column2 = ISNULL(users.Column2, groups.Column2)
from
works
left join users on
users.id = work.owner and
work.type = 1
left join groups on
groups.id = work.owner and
(work.type <> 1 OR work.type IS NULL)
If you need to use the same select repeatedly, you can create a table-valued function to wrap this up so you don't have to code it every time. I'll use the table example to show another alternative, using UNION ALL.
CREATE FUNCTION dbo.GetWorkData (#owner INT) -- assuming its a INT
RETURNS TABLE
AS
RETURN
SELECT
-- Your wanted columns here
FROM
works AS W
INNER JOIN users AS U ON W.owner = U.owner
WHERE
W.owner = #owner AND
W.type = 1
UNION ALL
SELECT
-- Your wanted columns here (must be same data type and order of previous SELECT)
FROM
works AS W
INNER JOIN groups AS U ON W.owner = U.owner
WHERE
W.owner = #owner AND
(W.type <> 1 OR W.type IS NULL)
You can use the function with APPLY:
SELECT
D.*
FROM
works AS W
CROSS APPLY dbo.GetWorkData(W.owner) AS D -- User "OUTER APPLY" if you want works that have no users or groups
You can look into Dynamic SQL. The main idea is that the SQL statement is constructed and compiled at runtime.
You can start here:
Link 1 - MSSQL tips.
or here: Link 2 - official microsoft documentation.
I edited the following query based on this page:
Selecting a Record With MAX Value
Select query :
select
Users.Id, Users.[Name], Users.Family, Users.BirthDate,
Users.Mobile, Users.[Description], Users.Email,
Users.UserName, Users.fatherName,
Users.archiveNumber, Users.[Address], Users.IsMarried,
Users.Mazhab,
Cities.CityName, Religions.PersianName, Users.Date_insert,
Users.ImageName,
MaghtaeTahsilis.[Name] as MaghtaeTahsilisName,
FieldStudies.[Name] as FieldStudiesName,
Eductionals.Institute, Eductionals.Moaddal,
Eductionals.FromYear, Eductionals.ToYear
from
Users
left outer join
Eductionals on Users.id = Eductionals.UserID
left outer join
MaghtaeTahsilis on Eductionals.MaghtaeID = MaghtaeTahsilis.ID
left outer join
Cities on Users.City_Id = Cities.Id
left outer join
Religions on Users.Relegion_ID = Religions.ID
left outer join
FieldStudies on Eductionals.FieldStudy_ID = FieldStudies.ID
where
Users.UserName = #code_melli
and Eductionals.MaghtaeID = (select MAX(MaghtaeID) from Eductionals
where Eductionals.UserID = Users.Id)
This command works correctly in choosing MAX value, But if the following statement has a NULL value, no row are returned. I want to show NULL value if it is NULL.
Your left outer joins are being turned into inner joins by the where conditions. Your query should look like:
select u.Id, u.[Name], u.Family, u.BirthDate, u.Mobile, u.[Description], u.Email, u.UserName, u.fatherName,
u.archiveNumber, u.[Address], u.IsMarried, u.Mazhab, c.CityName, r.PersianName, u.Date_insert, u.ImageName,
mt.[Name] As MaghtaeTahsilisName, fs.[Name] As FieldStudiesName, e.Institute, e.Moaddal, e.FromYear, e.ToYear
from Users u left outer join
Eductionals e
on u.id = e.UserID and
e.MaghtaeID = (select MAX(e2.MaghtaeID)
from Eductionals e2
where e2.UserID = u.Id
) left outer join
MaghtaeTahsilis mt
on e.MaghtaeID = mt.ID left outer join
Cities c
on u.City_Id = c.Id left outer join
Religions r
on u.Relegion_ID = r.ID left outer join
FieldStudies fs
on e.FieldStudy_ID = fs.ID
where u.UserName = #code_melli ;
Conditions on the first table -- in a chain of left joins should be in the where clause. On subsequent tables in the on clauses.
You'll notice that I also added table aliases so the query is easier to write and to read.
You can also use window functions:
from Users u left outer join
(select e2.*,
row_number() over (partition by e2.userId order by e2.MaghtaeID desc) as seqnum
from Eductionals e2
) e
on u.id = e.UserID and
e.seqnum = 1 left outer join
. . .
Reason for returning zero records when second query returns NULL is, when second query returns NULL, your SQL syntax become like this
And Eductionals.MaghtaeID=NULL
And probably Dbtable Educationals holds NULL values for field MaghtaeID.
So SQL fails above syntax and thus returns zero records.
Correct syntax for checking NULL values would be
And Eductionals.MaghtaeID is NULL
So please modify where condition in your query as follows which will return desired result.
where Users.UserName = #code_melli AND isnull(Eductionals.MaghtaeID,0) = isnull((select MAX(MaghtaeID) from Eductionals where Eductionals.UserID = Users.Id),0)
I'm querying on SQL Server 2016:
SELECT 1
FROM LINKEDSERVER1.DATABASE1.DBO.TABLE1 A with (nolock)
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE2 B with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE3 C with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE4 D with (nolock) ON (D.FIELD1 = C.FIELD1 AND D.CHAR_FIELD2 = B.VARCHAR_FIELD2 AND (D.FIELD3 = B.FIELD3 OR D.FIELD3 = B.FIELD4))
WHERE B.FIELD5 IN ('4472')
Result: Row is not returned
1 - If I change the condition AND D.CHAR_FIELD2 = B.VARCHAR_FIELD2 outside of the join:
SELECT 1
FROM LINKEDSERVER1.DATABASE1.DBO.TABLE1 A with (nolock)
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE2 B with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE3 C with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE4 D with (nolock) ON (D.FIELD1 = C.FIELD1 AND (D.FIELD3 = B.FIELD3 OR D.FIELD3 = B.FIELD4))
WHERE B.FIELD5 IN ('4472')
AND D.CHAR_FIELD2 = B.VARCHAR_FIELD2
Result: Row is returned
2 - If I remove the linked server on TABLE4:
SELECT 1
FROM LINKEDSERVER1.DATABASE1.DBO.TABLE1 A with (nolock)
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE2 B with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE3 C with (nolock) ON ...
LEFT JOIN TABLE4 D with (nolock) ON (D.FIELD1 = C.FIELD1 AND D.CHAR_FIELD2 = B.VARCHAR_FIELD2 AND (D.FIELD3 = B.FIELD3 OR D.FIELD3 = B.FIELD4))
WHERE B.FIELD5 IN ('4472')
Result: Row is returned
3 - If I run the same query on SQL Server 2005:
SELECT 1
FROM LINKEDSERVER1.DATABASE1.DBO.TABLE1 A with (nolock)
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE2 B with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE3 C with (nolock) ON ...
LEFT JOIN LINKEDSERVER1.DATABASE1.DBO.TABLE4 D with (nolock) ON (D.FIELD1 = C.FIELD1 AND D.CHAR_FIELD2 = B.VARCHAR_FIELD2 AND (D.FIELD3 = B.FIELD3 OR D.FIELD3 = B.FIELD4))
WHERE B.FIELD5 IN ('4472')
Result: Row is returned
I'm running SQL Server 2016 13.0.1601.5.
I couldn't find anything about this on SP1 and SP2.
Is this a known issue? Am I missing something?
Found the problem. I was checking the fields' collation, but the databases default collations are different.
I guess that because the fields are char and varchar, it is casting one of then and using default collation, then when remote query is executed, it doesn't find the record.
If I change default collation or force field collation, it works. If I disable "Use Remote Collation" on then linked server properties, it works too.
I am writing a stored procedure for a project in SQL Server 2014 and I have this code:
ALTER PROCEDURE FOF_MejorVendedor
AS
BEGIN
SELECT TOP 1
F.Nombre, Em.Nombre, (P.Precio * CA.Cantidad) as 'Ganancia'
FROM
dbo.FO_Carrito CA
JOIN
dbo.FO_Solicitud S on S.ID = CA.FK_SolicitudC
JOIN
dbo.FO_Recibo R ON R.FK_Solicitud = S.ID
JOIN
dbo.FO_Productos P ON P.ID = CA.FK_ProductosC
JOIN
dbo.FO_Cliente C ON C.ID = S.FK_Cliente
JOIN
dbo.FO_Estante E ON E.FK_Producto = P.ID
JOIN
dbo.FO_PasilloXDepartamento PD ON PD.FK_Estante = E.NumeroEstante
JOIN
dbo.FO_Encargado En ON En.ID = PD.FK_Encargado
JOIN
dbo.FO_Empleado Em ON Em.ID = En.FK_EmpleadoE
JOIN
dbo.FO_Departamento D ON D.ID = PD.FK_Departamento
JOIN
dbo.FO_Ferreteria F ON D.FK_Ferreteria = F.ID
JOIN
dbo.FO_EmpleadosXFerreteria EF ON EF.FK_Ferreterias = F.ID
GROUP BY
F.Nombre, Em.Nombre, (P.Precio * CA.Cantidad)
ORDER BY
Ganancia DESC
END
But I am only getting the Top 1 of 'Ganancia' but I want to get it for each distinct value in the column "F.Nombre". How can I modify the query?
You are retrieving the top record because you using Top 1 clause, did u believe !
so remove it and the
Group by
will show the result as distinct.