SQL Server query showing most recent distinct data - sql

I am trying to build a SQL query to recover only the most young record of a table (it has a Timestamp column already) where the item by which I want to filter appears several times, as shown in my table example:
.
Basically, I have a table1 with Id, Millis, fkName and Price, and a table2 with Id and Name.
In table1, items can appear several times with the same fkName.
What I need to achieve is building up a single query where I can list the last record for every fkName, so that I can get the most actual price for every item.
What I have tried so far is a query with
SELECT DISTINCT [table1].[Millis], [table2].[Name], [table1].[Price]
FROM [table1]
JOIN [table2] ON [table2].[Id] = [table1].[fkName]
ORDER BY [table2].[Name]
But I don't get the correct listing.
Any advice on this? Thanks in advance,

A simple and portable approach to this greatest-n-per-group problem is to filter with a subquery:
select t1.millis, t2.name, t1.price
from table1 t1
inner join table2 t2 on t2.id = t1.fkName
where t1.millis = (select max(t11.millis) from table1 t11 where t11.fkName = t1.fkName)
order by t1.millis desc

using Common Table Expression:
;with [LastPrice] as (
select [Millis], [Price], ROW_NUMBER() over (Partition by [fkName] order by [Millis] desc) rn
from [table1]
)
SELECT DISTINCT [LastPrice].[Millis],[table2].[Name],[LastPrice].[Price]
FROM [LastPrice]
JOIN [table2] ON [table2].[Id] = [LastPrice].[fkName]
WHERE [LastPrice].rn = 1
ORDER BY [table2].[Name]

Related

How to get latest date that is not greater then record date?

I have table with names with eomonth history.
I need to join another table that has information about "tests" performed on names:
The result table should show the latest ID and date of performed test but the date of test cannot be greater than the data month:
Any ideas how to perform this?
I am guessing that you want the most recent EOMONTH from the second table for each row in the first table. If that is the correct interpretation, then you can simply use apply:
select t1.*, t2.*
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.test_id = t1.test_id and t2.eomonth <= t1.test_date
order by t2.eomonth desc
) t2;
This join works perfectly:
from table1 a
left join table2 b on a.name = b.name and a.eomonth >= b.id_date and a.eomonth < LAG(b.id_date,1,'3000-01-01') OVER (PARTITION BY name ORDER BY b.id_date desc)

SQL Tables need to be appended, but not like JOINS

I've a scenario as below.
I've two tables, and a Common column/Key between the two.
I need Table2 data to be just appended to Table1 without repetition like JOINs.
If there are more rows in one table, other table rows can be NULL.
As shown in figure, Result Table has NULLs when there is no corresponding row count from Table2.
I tried using Joins, but I'm getting a result of 45 rows. But I should get 9 rows.
Thanks in advance.
Edit: Added my queries
SELECT DISTINCT
APPT.PRSN_ID
,APPT.SCHEDULEDAPPOINTMENTS
,APPT.OVERDUEAPPOINTMENTS
,Visit.ENCOUNTER_CATEGORY
,Visit.ENCOUNTER_TYPE
,Visit.ENCOUNTER_DATE
,Visit.ENCOUNTER_FOLLOWUP_DATE
FROM
APPOINTMENTS APPT
OUTER APPLY dbo.fn_GetVisitsOfAPerson(PROV.PRSN_ID) AS Visit
/***********************************************************/
--IN THE ABOVE QUERY, THE FUNCTION IS DEFINED AS BELOW
CREATE FUNCTION dbo.fn_GetVisitsOfAPerson(#PrsnID AS bigint)
RETURNS TABLE
AS
RETURN
(
SELECT
VISITS.PVISITS_PRSN_KEY
,DATA.HE_Category_Description AS 'ENCOUNTER_CATEGORY'
,DATA.HE_Type_Description AS 'ENCOUNTER_TYPE'
,VISITS.PVISITS_DATE AS 'ENCOUNTER_DATE'
,VISITS.PVISITS_FOLLOWUP_DATE AS 'ENCOUNTER_FOLLOWUP_DATE'
FROM
[HS_PRSN_HEALTH_VISITS] VISITS INNER JOIN
[HS_HealthEncounter_Table] DATA ON
ENCOUNTER.PVISITS_CATEGORY = DATA.HE_Category_Code AND
ENCOUNTER.PVISITS_TYPE = DATA.HE_Type_Code
WHERE
PVISITS_PRSN_KEY = #PrsnID
AND PVISITS_VOID = 0
)
GO
I cannot read your data tables, but I think you just need to introduce a row number.
It would be something like this:
select . . .
from (select t1.*, row_number() over (partition by key order by ??) as seqnum
from table1 t1
) full join
(select t2.*, row_number() over (partition by key order by ??) as seqnum
from table1 t2
) t2
on t1.key = t2.key and t1.seqnum = t2.seqnum;
Based on you wanting the 9 rows present in the Visit table it looks like you need an OUTER JOIN, something like:
SELECT DISTINCT
APPT.PRSN_ID
,APPT.SCHEDULEDAPPOINTMENTS
,APPT.OVERDUEAPPOINTMENTS
,Visit.ENCOUNTER_CATEGORY
,Visit.ENCOUNTER_TYPE
,Visit.ENCOUNTER_DATE
,Visit.ENCOUNTER_FOLLOWUP_DATE
FROM Visit
LEFT OUTER JOIN
APPOINTMENTS APPT
ON Visit.key = APP.key

Using MAX when selecting a high number of fields in a query

I understand some varieties of this question have been asked, but I could not find an answer to my specific scenario.
My query has over 50 fields being selected, and only one of them is an aggregate, using MAX(). On the GROUP BY clause, I would only like to pass two specific fields, name and UserID, not all 50 to make the query run. See small subset below.
SELECT
t1.name,
MAX(t2.id) as UserID,
t3.age,
t3.height,
t3.dob,
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
LEFT JOIN table3 t3 ON t1.id = t3.id
GROUP BY t1.name, UserID
Is there any workaround or better approach to accomplish my goal?
The database is SQL Server and any help would be greatly appreciated.
Hmmm . . . What values do you want for the other fields? If you want the max() of one column for each id and code, you can do:
select t.*
from (select t.*, max(col) over (partition by id, code) as maxcol
from t
) t
where col = maxcol;
Given that id might be unique, you might want the maximum id as well as the other columns for each code:
select t.*
from (select t.*, max(id) over (partition by code) as maxid
from t
) t
where id = maxid;

how to get single row form group

I want a query which will give me desired output ,I am using following query
select table1.name1,table2.address
from table1 join table2
on(table1.key=table2.key);
it is giving me result After join nut I only need single row for each key.
Any help will be appreciated.
If any combination is allowed but only one row for each key then try this:
select table1.name1, MAX(table2.address) address
from table1
join table2
on table1.key=table2.key
group by table1.name1
try like this
select *
from (select table2.address,
rank() over ( partition by table1.name1 order by table1.key) rn
from table1 join table2 on(table1.key=table2.key))
where rn = 1

SQL - remove duplicates from left join

I'm creating a joined view of two tables, but am getting unwanted duplicates from table2.
For example: table1 has 9000 records and I need the resulting view to contain exactly the same; table2 may have multiple records with the same FKID but I only want to return one record (random chosen is ok with my customer). I have the following code that works correctly, but performance is slower than desired (over 14 seconds).
SELECT
OBJECTID
, PKID
,(SELECT TOP (1) SUBDIVISIO
FROM dbo.table2 AS t2
WHERE (t1.PKID = t2.FKID)) AS ProjectName
,(SELECT TOP (1) ASBUILT1
FROM dbo.table2 AS t2
WHERE (t1.PKID = t2.FKID)) AS Asbuilt
FROM dbo.table1 AS t1
Is there a way to do something similar with joins to speed up performance?
I'm using SQL Server 2008 R2.
I got close with the following code (~.5 seconds), but 'Distinct' only filters out records when all columns are duplicate (rather than just the FKID).
SELECT
t1.OBJECTID
,t1.PKID
,t2.ProjectName
,t2.Asbuilt
FROM dbo.table1 AS t1
LEFT JOIN (SELECT
DISTINCT FKID
,ProjectName
,Asbuilt
FROM dbo.table2) t2
ON t1.PKID = t2.FKID
table examples
table1 table2
OID, PKID FKID, ProjectName, Asbuilt
1, id1 id1, P1, AB1
2, id2 id1, P5, AB5
3, id4 id2, P10, AB2
5, id5 id5, P4, AB4
In the above example returned records should be id5/P4/AB4, id2/P10/AB2, and (id1/P1/AB1 OR id1/P5/AB5)
My search came up with similar questions, but none that resolved my problem. link, link
Thanks in advance for your help. This is my first post so let me know if I've broken any rules.
This will give the results you requested and should have the best performance.
SELECT
OBJECTID
, PKID
, t2.SUBDIVISIO,
, t2.ASBUILT1
FROM dbo.table1 AS t1
OUTER APPLY (
SELECT TOP 1 *
FROM dbo.table2 AS t2
WHERE t1.PKID = t2.FKID
) AS t2
Your original query is producing arbitrary values for the two columns (the use of top with no order by). You can get the same effect with this:
SELECT t1.OBJECTID, t1.PKID, t2.ProjectName, t2.Asbuilt
FROM dbo.table1 t1 LEFT JOIN
(SELECT FKID, min(ProjectName) as ProjectName, MIN(asBuilt) as AsBuilt
FROM dbo.table2
group by fkid
) t2
ON t1.PKID = t2.FKID
This version replaces the distinct with a group by.
To get a truly random row in SQL Server (which your syntax suggests you are using), try this:
SELECT t1.OBJECTID, t1.PKID, t2.ProjectName, t2.Asbuilt
FROM dbo.table1 t1 LEFT JOIN
(SELECT FKID, ProjectName, AsBuilt,
ROW_NUMBER() over (PARTITION by fkid order by newid()) as seqnum
FROM dbo.table2
) t2
ON t1.PKID = t2.FKID and t2.seqnum = 1
This assumes version 2005 or greater.
If you want described result, you need to use INNER JOIN and following query will satisfy your need:
SELECT
t1.OID,
t1.PKID,
MAX(t2.ProjectName) AS ProjectName,
MAX(t2.Asbuilt) AS Asbuilt
FROM table1 t1
JOIN table2 t2 ON t1.PKID = t2.FKID
GROUP BY
t1.OID,
t1.PKID
If you want to see all rows from left table (table1) whether it has pair in right table or not, then use LEFT JOIN and same query will gave you desired result.
EDITED
This construction has good performance, and you dont need to use subqueries.