CROSS APPLY Returning more than expected number of rows - sql-server

I would like to only return one row from the CROSS APPLY, however I am returning multiple OwnershipID rows, different from what I get in the eSub subquery. Can someone please point out what I'm doing wrong?
SELECT
o2.OwnershipID,
eSub.AssetID,
esub.EntityID,
esub.Entity
FROM tblOwnership o2
CROSS APPLY
(
SELECT TOP 1
a1.AssetID,
e1.EntityID,
e1.Entity,
o1.OwnershipID
FROM tblAssets a1
INNER JOIN tblOwnership o1 ON a1.AssetID = o1.AssetID
INNER JOIN tblEntity e1 ON o1.EntityID = e1.EntityID
WHERE 1=1
AND o1.OwnershipID = o2.OwnershipID
AND a1.AssetID = 1996323640
ORDER BY o1.OwnershipID DESC, o1.[Date] DESC
) eSub
WHERE 1=1
AND o2.AssetID = 1996323640
ORDER BY o2.OwnershipID DESC

I would like to return the top 1 ownershipID for each assetID in the table.
If you want to look at all records for a given AssetID, then you should only apply a range on that column in the where clause of your cross apply. Each combination of [AssetID, EntityID, OwnershipID] appears to be unique in your data. If you add ranges on all three fields, then there will be only one matching record (itself).
Working with your fiddle I came up with this.
SELECT o2.AssetID,
o2.EntityID,
o2.OwnershipID as 'o2OwnID',
eSub.OwnershipID as 'eOwnID'
FROM tblOwnership o2
CROSS APPLY
(
SELECT TOP 1 o1.OwnershipID
FROM tblOwnership o1
WHERE o1.AssetID = o2.AssetID
/*AND o1.EntityID = o2.EntityID
AND o1.OwnershipID = o2.OwnershipID*/
ORDER BY o1.OwnershipID DESC
) eSub
ORDER BY o2.OwnershipID DESC

Related

VIEWS with SELECT inside conditions delaying the query

In one of my SQL views I am using an inline select statement with a where clause.
The outline of my view is like
ALTER VIEW [dbo].[vw_autumn]
AS
SELECT
BookNumber, Title, shopNo
FROM
(SELECT
BookNumber, Title, shopNO
FROM
(SELECT DISTINCT
(sum_vnr) AS BookNumber,
navn1 AS Title,
tik AS ShopNO,
ROW_NUMBER() OVER (PARTITION BY sum_vnr, tik ORDER BY sum_vnr DESC) AS rownumber
FROM
sum s
INNER JOIN
hod h ON s.tik = h.tik
WHERE
s.aar = (SELECT currentyear
FROM SemesterInfo
WHERE SemName = 'Autumn')
AND CAST(s.sum_vnr AS BIGINT) > 10000
AND (s.id LIKE 'h%' OR s.id LIKE 'H%' OR s.id LIKE 'j%'
OR s.id LIKE 'J%')) a
WHERE rownumber = 1
) b
LEFT JOIN (
------
) p ON b.ShopNO = p.tikk
AND b.ISBN = p.vnr
LEFT JOIN table_k k ON p.aar = k.aar
GO
And if I remove the WHERE clause of
WHERE
s.aar = (SELECT currentyear
FROM SemesterInfo
WHERE SemName = 'Autumn')
and shorten it to
WHERE s.aar =19
I am getting the result of view very quickly. But I am trying to add some dynamic nature to this query and selecting this constant from a settings table
Any thoughts on this? Why is the query taking an indefinite time to load with an inline Where clause?
:try with IN insted of =
WHERE
s.aar in (SELECT currentyear
FROM SemesterInfo
WHERE SemName = 'Autumn')
Rewrite the subquery as a join.
INNER JOIN SemesterInfo si
ON s.aer = si.currentYear
WHERE si.SemName = 'Autumn'
If that doesn't do it, consider keeping this syntax and creating an index on SemName

How to join one select with another when the first one not always returns a value for specific row?

I have a complex query to retrieve some results:
EDITED QUERY (added the UNION ALL):
SELECT t.*
FROM (
SELECT
dbo.Intervencao.INT_Processo, analista,
ETS.ETS_Sigla, ATC.ATC_Sigla, PAT.PAT_Sigla, dbo.Assunto.SNT_Peso,
CASE
WHEN ETS.ETS_Sigla = 'PE' AND (PAT.PAT_Sigla = 'LIB' OR PAT.PAT_Sigla = 'LBR') THEN (0.3*SNT_Peso)
WHEN ETS.ETS_Sigla = 'CD' THEN (0.3*SNT_Peso)*0.3
ELSE SNT_Peso
END AS PESOAREA,
CASE
WHEN a.max_TEA_FimTarefa IS NULL THEN a.max_TEA_InicioTarefa
ELSE a.max_TEA_FimTarefa
END AS DATA_INICIO_TERMINO,
ROW_NUMBER() OVER (PARTITION BY ATC.ATC_Sigla, a.SRV_Id ORDER BY TEA_FimTarefa DESC) AS seqnum
FROM dbo.Tarefa AS t
INNER JOIN (
SELECT
MAX(dbo.TarefaEtapaAreaTecnica.TEA_InicioTarefa) AS max_TEA_InicioTarefa,
MAX (dbo.TarefaEtapaAreaTecnica.TEA_FimTarefa) AS max_TEA_FimTarefa,
dbo.Pessoa.PFJ_Descri AS analista, dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id
FROM dbo.TarefaEtapaAreaTecnica
LEFT JOIN dbo.Tarefa ON dbo.TarefaEtapaAreaTecnica.TRF_Id = dbo.Tarefa.TRF_Id
LEFT JOIN dbo.AreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.AreaTecnica.ATC_Id
LEFT JOIN dbo.ServicoAreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.ServicoAreaTecnica.ATC_Id
AND dbo.Tarefa.SRV_Id = dbo.ServicoAreaTecnica.SRV_Id
INNER JOIN dbo.Pessoa ON dbo.Pessoa.PFJ_Id = dbo.ServicoAreaTecnica.PFJ_Id_Analista
GROUP BY dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id, dbo.Pessoa.PFJ_Descri
) AS a ON t.SRV_Id = a.SRV_Id
INNER JOIN dbo.TarefaEtapaAreaTecnica AS TarefaEtapaAreaTecnica_1 ON
t.TRF_Id = TarefaEtapaAreaTecnica_1.TRF_Id
AND a.ATC_Id = TarefaEtapaAreaTecnica_1.ATC_Id
AND a.max_TEA_InicioTarefa = TarefaEtapaAreaTecnica_1.TEA_InicioTarefa
LEFT JOIN AreaTecnica ATC ON TarefaEtapaAreaTecnica_1.ATC_Id = ATC.ATC_Id
LEFT JOIN Etapa ETS ON TarefaEtapaAreaTecnica_1.ETS_Id = ETS.ETS_Id
LEFT JOIN ParecerTipo PAT ON TarefaEtapaAreaTecnica_1.PAT_Id = PAT.PAT_Id
LEFT OUTER JOIN dbo.Servico ON a.SRV_Id = dbo.Servico.SRV_Id
INNER JOIN dbo.Intervencao ON dbo.Servico.INT_Id = dbo.Intervencao.INT_Id
LEFT JOIN dbo.Assunto ON dbo.Servico.SNT_Id = dbo.Assunto.SNT_Id
) t
The result is following:
It works good, the problem is that I was asked that if when a row is not present on this query, it must contain values from another table (ServicoAreaTecnica), so I got this query for the other table based on crucial information of the first query. So if I UNION ALL I get this:
Query1 +
UNION ALL
SELECT INN.INT_Processo,
PES.PFJ_Descri,
NULL, --ETS.ETS_Sigla,
ART.ATC_Sigla,
NULL ,--PAT.PAT_Sigla,
ASS.SNT_Peso,
NULL, --PESOAREA
NULL, --DATA_INICIO_TERMINO
NULL --seqnum
FROM dbo.ServicoAreaTecnica AS SAT
INNER JOIN dbo.AreaTecnica AS ART ON ART.ATC_Id = SAT.ATC_Id
INNER JOIN dbo.Servico AS SER ON SER.SRV_Id = SAT.SRV_Id
INNER JOIN dbo.Assunto AS ASS ON ASS.SNT_Id = SER.SNT_Id
INNER JOIN dbo.Intervencao AS INN ON INN.INT_Id = SER.INT_Id
INNER JOIN dbo.Pessoa AS PES ON PES.PFJ_Id = SAT.PFJ_Id_Analista
The result is following:
So what I want to do is to remove row number 1 because row number 2 exists on the first query, I think I got it explained better this time. The result should be only row number 1, row number 2 would appear only if query 1 doesn't retrieve a row for that particular INN.INT_Processo.
Thanks!
Ok, there are two ways to reduce your record set. Given that you've already written the code to produce the table with the extra rows, it might be easiest to just add code to reduce that:
Select * from
(Select *
, Row_Number() over
(partition by IntProcesso, Analista order by ISNULL(seqnum, 0) desc) as RN
from MyResults) a
where RN = 1
This will assign row_number 1 to any rows that came from your first query, or to any rows from the second query that do not have matches in the first query, then filter out extra rows.
You could also use outer joins with isnull or coalesce, as others have suggested. Something like this:
Select ISNULL(a.IntProcesso, b.IntProcesso) as IntProcesso
, ISNULL(a.Analista, b.Analista) as Analista
, ISNULL(a.ETSsigla, b.ETSsigla) as ETSsigla
[repeat for the rest of your columns]
from Table1 a
full outer join Table2 b
on a.IntProcesso = b.IntProcesso and a.Analista = b.Analista
Your code is hard to read, because of the lengthy names of everything (and to be honest, the fact that they're in a language I don't speak also makes it a lot harder).
But how about: replacing your INNER JOINs with LEFT JOINs, adding more LEFT JOINs to draw in the alternative tables, and introducing ISNULL clauses for each variable you want in the results?
If you do something like ... Query1 Right Join Query2 On ... that should get only the rows in Query2 that don't appear in Query 1.

Duplicate record after joining two tables

I am currently having trouble with my query after joining two tables I am getting duplicated records. What i want to do is get the details from table 1 and the payment record from table 2 with same date.. here is my query.
SELECT dbo.tblautoipekonek.ipno,
dbo.tblautoipekonek.awbno,
dbo.tblautoipekonek.ipamount,
dbo.tblautoipekonek.orno,
dbo.tbladdfunds.username,
dbo.tbladdfunds.newctfbal,
dbo.tbladdfunds.addedctfamt,
dbo.tbladdfunds.oldctfbal,
dbo.tbladdfunds.newipbal,
dbo.tbladdfunds.addedipamt,
dbo.tbladdfunds.oldipbal,
dbo.tbladdfunds.date,
dbo.tblautoipekonek.date AS Expr1
FROM dbo.tblautoipekonek
LEFT OUTER JOIN dbo.tbladdfunds
ON dbo.tblautoipekonek.date = dbo.tbladdfunds.date
WHERE
( dbo.tblautoipekonek.date = '06/06/2014' )
Hi you can use "Distinct" keyword at after "select" keyword. it will get the single record.
Good to replace dbo.tablename with alias name give to tablename as
select
distinct
auto.IPNo, ... ---here you can add other column of this table.
fund.AddedCTFAmt --same thing done here.
FROM tblAutoIPEkonek auto
LEFT OUTER JOIN dbo.tblAddfunds fund
ON auto.Date = fund.Date --try to add more join condition so filteration done here of data which is fastest/
WHERE (auto.Date = '06/06/2014')
SELECT DISTINCT dbo.tblautoipekonek.ipno,
dbo.tblautoipekonek.awbno,
dbo.tblautoipekonek.ipamount,
dbo.tblautoipekonek.orno,
dbo.tbladdfunds.username,
dbo.tbladdfunds.newctfbal,
dbo.tbladdfunds.addedctfamt,
dbo.tbladdfunds.oldctfbal,
dbo.tbladdfunds.newipbal,
dbo.tbladdfunds.addedipamt,
dbo.tbladdfunds.oldipbal,
dbo.tbladdfunds.date,
dbo.tblautoipekonek.date AS Expr1
FROM dbo.tblautoipekonek
LEFT OUTER JOIN dbo.tbladdfunds
ON dbo.tblautoipekonek.date = dbo.tbladdfunds.date
WHERE
( dbo.tblautoipekonek.date = '06/06/2014' )
GROUP BY dbo.tblautoipekonek.ipno,
dbo.tblautoipekonek.awbno,
dbo.tblautoipekonek.ipamount,
dbo.tblautoipekonek.orno,
dbo.tbladdfunds.username,
dbo.tbladdfunds.newctfbal,
dbo.tbladdfunds.addedctfamt,
dbo.tbladdfunds.oldctfbal,
dbo.tbladdfunds.newipbal,
dbo.tbladdfunds.addedipamt,
dbo.tbladdfunds.oldipbal,
dbo.tbladdfunds.date,
dbo.tblautoipekonek.date AS Expr1
Not sure if this will work for you but this is what I would use:
SELECT
p.ipno,
p.awbno,
p.ipamount,
p.orno,
f.username,
f.newctfbal,
f.addedctfamt,
f.oldctfbal,
f.newipbal,
f.addedipamt,
f.oldipbal,
f.date,
p.date Expr1
FROM
dbo.tblautoipekonek p
CROSS APPLY
(
SELECT TOP 1
*
FROM
dbo.tbladdfunds f
WHERE
p.date = f.date
ORDER BY
f.newipbal DESC
) f
This will get you one line from each entry in dbo.tblautoipekonek joined with the matching date entry from dbo.tbladdfunds which has the highest value in newipbal

SQL Select random from multiple table and order by specific criteria on one table

I need to select a random record from 3 tables and ensure I am ordering by photoOrder
Select TOP 1(a.id), a.mls_number, a.parcel_name, a.property_type, a.ownership_type, b.filename, b.photoOrder, c.county_Name
From property as a
Inner JOIN
listingPhotos as b on a.id = b.ListingID
LEFT JOIN
counties as C on a.county_name = c.id
WHERE a.isCommercial = 'True'
Order By NEWID()
So this query works, but I need to ensure that the b.filename record is ordered by b.photoOrder and thus the b.photoOrder should always be 1.
The b table (listing photos) has multiple photo files per property and I need to only select the photo that is 1st in the photo order.
Thanks
You could subquery your listingPhotos table and limit to WHERE PhotoOrder = 1:
Select TOP 1(a.id), a.mls_number, a.parcel_name, a.property_type, a.ownership_type, b.filename, b.photoOrder, c.county_Name
From property as a
Inner JOIN
(SELECT ListingID , filename, PhotoOrder FROM listingPhotos WHERE PhotoORder = 1
) as b on a.id = b.ListingID
LEFT JOIN
counties as C on a.county_name = c.id
WHERE a.isCommercial = 'True'
Order By NEWID()

Join the table valued function in the query

I have one table vwuser. I want join this table with the table valued function fnuserrank(userID). So I need to cross apply with table valued function:
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
For each userID it generates multiple records. I only want the last record for each empid that does not have a Rank of Term(inated). How can I do this?
Data:
HistoryID empid Rank MonitorDate
1 A1 E1 2012-8-9
2 A1 E2 2012-9-12
3 A1 Term 2012-10-13
4 A2 E3 2011-10-09
5 A2 TERM 2012-11-9
From this 2nd record and 4th record must be selected.
In SQL Server 2005+ you can use this Common Table Expression (CTE) to determine the latest record by MonitorDate that doesn't have a Rank of 'Term':
WITH EmployeeData AS
(
SELECT *
, ROW_NUMBER() OVER (PARTITION BY empId, ORDER BY MonitorDate DESC) AS RowNumber
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
WHERE Rank != 'Term'
)
SELECT *
FROM EmployeeData AS ed
WHERE ed.RowNumber = 1;
Note: The statement before this CTE will need to end in a semi-colon. Because of this, I have seen many people write them like ;WITH EmployeeData AS...
You'll have to play with this. Having trouble mocking your schema on sqlfiddle.
Select bar.*
from
(
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
where rank != 'TERM'
) foo
left join
(
SELECT *
FROM vwuser AS b
CROSS APPLY fnuserrank(b.userid)
where rank != 'TERM'
) bar
on foo.empId = bar.empId
and foo.MonitorDate > bar.MonitorDate
where bar.empid is null
I always need to test out left outers on dates being higher. The way it works is you do a left outer. Every row EXCEPT one per user has row(s) with a higher monitor date. That one row is the one you want. I usually use an example from my code, but i'm on the wrong laptop. to get it working you can select foo., bar. and look at the results and spot the row you want and make the condition correct.
You could also do this, which is easier to remember
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
) foo
join
(
select empid, max(monitordate) maxdate
FROM vwuser AS b
CROSS APPLY fnuserrank(b.userid)
where rank != 'TERM'
) bar
on foo.empid = bar.empid
and foo.monitordate = bar.maxdate
I usually prefer to use set based logic over aggregate functions, but whatever works. You can tweak it also by caching the results of your TVF join into a table variable.
EDIT:
http://www.sqlfiddle.com/#!3/613e4/17 - I mocked up your TVF here. Apparently sqlfiddle didn't like "go".
select foo.*, bar.*
from
(
SELECT f.*
FROM vwuser AS a
join fnuserrank f
on a.empid = f.empid
where rank != 'TERM'
) foo
left join
(
SELECT f1.empid [barempid], f1.monitordate [barmonitordate]
FROM vwuser AS b
join fnuserrank f1
on b.empid = f1.empid
where rank != 'TERM'
) bar
on foo.empId = bar.barempid
and foo.MonitorDate > bar.barmonitordate
where bar.barempid is null

Resources