Improve Inner-Join/Temp Table Query - sql-server

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

Related

SQL Server 2017 vs SQL Server 2012 performance problem

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.

how to use aggregate query result as column in another query having joins using stored procedures in SQL Server

i have a inner join query in stored procedure which is working fine. i need to inject a aggregate query in it so that it show an aggregated result in a new column
https://drive.google.com/file/d/1tAIEACvEnG7sAisSoE2crYRrzCjIcvST/view?usp=sharing
i tried to inject aggregate query as a column TotalQty in my query
SELECT dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name AS ProductName, dbo.SOD.SalePrice
,TotalQty = (select SUM(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B' )
FROM dbo.SOD INNER JOIN
dbo.Product ON dbo.SOD.ProductId = dbo.Product.Id RIGHT JOIN
dbo.SO ON dbo.SOD.SOId = dbo.SO.Id INNER JOIN
dbo.Customer ON dbo.SO.CustomerId = dbo.Customer.Id
WHERE (dbo.SO.Id = '68BD0F69-B957-439F-9AD0-180DF23EF42B')
But it says
Column 'dbo.SO.Id' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.
or any other good Technique suggested will be appreciated.
so change AS :
SELECT dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name AS ProductName, dbo.SOD.SalePrice
,(select count(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B') AS TotalQty
FROM dbo.SOD INNER JOIN
dbo.Product ON dbo.SOD.ProductId = dbo.Product.Id RIGHT JOIN
dbo.SO ON dbo.SOD.SOId = dbo.SO.Id INNER JOIN
dbo.Customer ON dbo.SO.CustomerId = dbo.Customer.Id
WHERE (dbo.SO.Id = '68BD0F69-B957-439F-9AD0-180DF23EF42B')
As in the internal query, your characteristic is you used the o.SOId field on where and in other hand used count aggregate function so you should:
SELECT dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name AS ProductName,
dbo.SOD.SalePrice
,count(dbo.SOD.Quantity) AS TotalQty
FROM dbo.SOD INNER JOIN
dbo.Product ON dbo.SOD.ProductId = dbo.Product.Id RIGHT JOIN
dbo.SO ON dbo.SOD.SOId = dbo.SO.Id INNER JOIN
dbo.Customer ON dbo.SO.CustomerId = dbo.Customer.Id
WHERE (dbo.SO.Id = '68BD0F69-B957-439F-9AD0-180DF23EF42B')
group by
dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name , dbo.SOD.SalePrice
Which will have the same output.
Generally speaking, you encourage others to help if you provide a MVCE. Using cryptic table names (are they tables? or views perhaps?) is not a healthy practice. In addition, it is not clear what you are trying to achieve with your subquery. You attempted to use count but you label the value as "TotalQty" and you replied to a suggestion using "sum". Very confusing.
So since we don't have your tables, I used the common MS sample database AdventureWorks. Below are two examples of counting the quantity values from the detail table.
select Ord.SalesOrderID, Det.SalesOrderDetailID,
Cust.AccountNumber as CustName, -- too lazy to get actual name
Prd.Name as ProductName,
Det.UnitPrice
,Counted.TotalQty
-- TotalQty = (select count(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B' )
from Sales.SalesOrderHeader as Ord
inner join Sales.SalesOrderDetail as Det on Ord.SalesOrderID = Det.SalesOrderID
inner join Production.Product as Prd on Det.ProductID = Prd.ProductID
inner join Sales.Customer as Cust on Ord.CustomerID = Cust.CustomerID
cross apply (select count(DetCnt.OrderQty) as TotalQty from Sales.SalesOrderDetail as DetCnt where DetCnt.SalesOrderID = Det.SalesOrderID) as Counted
where Ord.SalesOrderID = 43659
select Ord.SalesOrderID, Det.SalesOrderDetailID,
Cust.AccountNumber as CustName, -- too lazy to get actual name
Prd.Name as ProductName,
Det.UnitPrice
, TotalQty = (select count(DetCnt.OrderQty) from Sales.SalesOrderDetail as DetCnt where DetCnt.SalesOrderID = Det.SalesOrderID)
-- TotalQty = (select count(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B' )
from Sales.SalesOrderHeader as Ord
inner join Sales.SalesOrderDetail as Det on Ord.SalesOrderID = Det.SalesOrderID
inner join Production.Product as Prd on Det.ProductID = Prd.ProductID
inner join Sales.Customer as Cust on Ord.CustomerID = Cust.CustomerID
where Ord.SalesOrderID = 43659
I think that interpretation is correct but I don't know your schema. I added the PK of the detail table to help "see" the relationship between Order and Detail.
Examine the code closely. Notice how the query only refers to the specific PK value once (this would be your procedure's parameter). You use correlations and joins to limit the results as needed. And notice how much easier it is to understand the query since it uses names that are actual words - SalesOrder vs. SO. I don't think it makes much sense to right join your Detail table to the Order table - seems like a mistake. Your aggregation attempt is odd so I can't say if the value computed by these queries is correct.
I'll also note that you should not be passing the PK value of your table using a nvarchar parameter. Use the correct datatype to avoid the possibility that someone attempts to pass an actual string (e.g., N'Pick me') instead of a GUID value.

Select row with max value in multiple where condition

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)

Using sub-queries and filter in WHERE clause while joining tables

SELECT DISTINCT(t1.Ticker),t2.SecurityID,t2.ClosePrice,t2.QuoteDateTime FROM [Hub].[SecurityMaster].[SecurityMasterDetails] as t1
INNER JOIN [Hub].[SecurityMaster].[SecurityPrices] as t2
ON t2.SecurityID =t1.SecurityID
WHERE t2.QuoteDateTime IN (SELECT max(QuoteDateTime) FROM [Hub].[SecurityMaster].[SecurityPrices]) AND t1.SecurityTypeName = 'REIT'
I get an output with no data. The subquery doesn't run along with the other filter in the WHERE clause. I am not sure what I am doing wrong. Can somebody please help!
If you are trying to get the lastest row from SecurityPrices for each Ticker, one option is to use cross apply():
select --distinct /* distinct not needed if `Ticker` is unique on `smd`
smd.Ticker
, sp.SecurityID
, sp.ClosePrice
, sp.QuoteDateTime
from [Hub].[SecurityMaster].[SecurityMasterDetails] as smd
cross apply (
select top 1
i.SecurityID
, i.ClosePrice
, i.QuoteDateTime
from [Hub].[SecurityMaster].[SecurityPrices] i
where i.SecurityID = smd.SecurityID
order by i.QuoteDateTime desc
) as sp
where SecurityTypeName = 'REIT' /* which table does this column belong to? */
I think your query would be
SELECT DISTINCT TOP 1 WITH TIES
t1.Ticker,
t2.SecurityID,
t2.ClosePrice,
t2.QuoteDateTime
FROM [Hub].[SecurityMaster].[SecurityMasterDetails] as t1
INNER JOIN [Hub].[SecurityMaster].[SecurityPrices] as t2 ON t2.SecurityID =t1.SecurityID
WHERE SecurityTypeName = 'REIT'
ORDER BY t2.QuoteDateTime DESC
You aren't getting results because the max(QuoteDateTime) record doesn't have SecurityTypeName = 'REIT'. I think you want the max(QuoteDateTime) for this SecurityTypeName, so this can be done with an INNER JOIN.
SELECT DISTINCT
(t1.Ticker),
t2.SecurityID,
t2.ClosePrice,
t2.QuoteDateTime
FROM [Hub].[SecurityMaster].[SecurityMasterDetails] as t1
INNER JOIN [Hub].[SecurityMaster].[SecurityPrices] as t2
ON t2.SecurityID =t1.SecurityID
INNER JOIN
(SELECT max(QuoteDateTime) DT FROM [Hub].[SecurityMaster].[SecurityPrices]) P on P.DT = t2.QuoteDateTime
WHERE SecurityTypeName = 'REIT'
EDIT
Your data doesn't have what you think it does, I suspect. Here is how you can check...
--Find the SecurityID that matches the max date
SELECT
SecurityID ,
max(QuoteDateTime) DT
FROM [Hub].[SecurityMaster].[SecurityPrices]
GROUP BY SecurityID
--I'm betting this ID isn't in your SecurityMasterDetails where the Type is REIT
SELECT DISTINCT
SecurityID
FROM SecurityMasterDetails
WHERE SecurityTypeName = 'REIT'
Since the SecurityID returned in the first query isn't in the second query result set, you are going to get NULL results.

Get distinct rows when filtering and using dynamic order by

My first version of the question was confusing, I need to make smaller chunks.
If a user can filter products from a website, one product should occur only once in the list.
Because of joins this code gives me two same products, how do I solve that?
I think I need a solution without using distinct because it will give me headache later on.
code from AW2012:
declare #safetystocklevel int
set #safetystocklevel = 1000
declare #status int
set #status = 2
select * from Production.Product p
inner join Purchasing.ProductVendor pv on p.ProductID = pv.ProductID
inner join Purchasing.Vendor v on v.BusinessEntityID = pv.BusinessEntityID
inner join Production.ProductDocument pd on p.ProductID = pd.ProductID
inner join Production.Document d on d.DocumentNode = pd.DocumentNode
WHERE
(#safetystocklevel = '' or p.SafetyStockLevel = #safetystocklevel)
and (#status = '' or d.Status = #status)
output:
ProductId Name
506 Reflector
506 Reflector
Edit:
Thanks, I now use Group by to get distinct rows.
Yeah, maybe using group by works for me, Im gonna do some testing now.....
Hi again
I want all products to be searchable, so I guess I need left outer joins to achieve that.
When I add dynamic order by I get into trouble, more rows are added.
Probably because I must add poh.Status to the group by.
There are 504 rows in the product table, this query returns 776 rows.
(I have removed the filtering in WHERE since it is not interesting now, and Im joining to other tables now just to get more rows to play with)
Code:
declare #sortType nvarchar(50)
set #sortType = 'Status'
select p.ProductID,
CASE WHEN #sortType = 'Status' THEN poh.Status END as Status,
CASE WHEN #sortType = 'ProductId' THEN p.ProductID END as ProductId
from Production.Product p
left outer join Purchasing.PurchaseOrderDetail pod on p.ProductID = pod.ProductID
left outer join Purchasing.PurchaseOrderHeader poh on poh.PurchaseOrderID = pod.PurchaseOrderID
left outer join Production.ProductDocument ppd on ppd.ProductID = p.ProductID
left outer join Production.Document pd on pd.DocumentNode = ppd.DocumentNode
group by p.ProductID, poh.Status
ORDER BY
CASE WHEN #sortType = 'Status' THEN poh.Status END ASC,
CASE WHEN #sortType = 'ProductId' THEN p.ProductID END ASC
You can use Group By ProductId, Name, to select the single row, if you are not planning to include distinct. But I'll prefer "distinct" if you are not using any aggregate value in select clause.
select p.ProductId, p.Name from Production.Product p
inner join Purchasing.ProductVendor pv on p.ProductID = pv.ProductID
inner join Purchasing.Vendor v on v.BusinessEntityID = pv.BusinessEntityID
inner join Production.ProductDocument pd on p.ProductID = pd.ProductID
inner join Production.Document d on d.DocumentNode = pd.DocumentNode
WHERE
(#safetystocklevel = '' or p.SafetyStockLevel = #safetystocklevel)
and (#status = '' or d.Status = #status)
GROUP BY p.ProductId, p.Name

Resources