How to Use Select top 1 sub query with Left join in SQL - sql

i am trying to execute this query but it does not work.Kindly Help me for this solution i want to select top 1 image against related post from sub query with left join
SELECT DISTINCT tblAdvertisement.AdvID,
tblAdvertisement.CityName,
tblAdvertisement.Model,
tblAdvertisement.Year,
tblAdvertisement.Mileage,
tblAdvertisement.imgPath,
tblAdvertisement.Price,
tblAdvertisement.VoteScore,
tblLike.isLike
FROM tblAdvertisement
LEFT JOIN tblimg
(
SELECT TOP 1
ImgPath
FROM tblimg ) AS
ON tblAdvertisement.AdvID = tblimg.AdvID
LEFT JOIN tblLike
ON tblAdvertisement.AdvID = tblLike.AdvID
AND tblAdvertisement.UserID = #userID
ORDER BY AdvID DESC

You need to use OUTER APPLY:
SELECT DISTINCT A.AdvID,
A.CityName,
A.Model,
A.Year,
A.Mileage,
I.imgPath,
A.Price,
A.VoteScore,
L.isLike
FROM tblAdvertisement A
OUTER APPLY ( SELECT TOP 1
ImgPath
FROM tblimg
WHERE AdvID = A.AdvID
ORDER BY SomeColumnToOrderBy) I
LEFT JOIN tblLike L
ON A.AdvID = L.AdvID
AND A.UserID = #userID
ORDER BY A.AdvID DESC;
Please notice that if you need the TOP 1 image, you should be doing an ORDER BY, otherwise you would be getting some arbitrary row instead of the one you actually want.

Related

Select max column from joined tables

The joined tables will result as a view like below. I wish to select just 1 record of the max id or prod_month column.
con_model srt_value_current con_id prod_month id
model 4 49 37 45145
model 4 49 38 45726
SELECT DISTINCT TOP (100) PERCENT dbo.DM_TBL_CONFIGURATION_MODEL.con_model, dbo.SRT_Data.SRT_VALUE_CURRENT, dbo.DM_TBL_CONFIGURATION_MODEL.con_id, dbo.SRT_Data.ID, dbo.SRT_Data.PROD_MONTH
FROM dbo.DM_TBL_CONFIGURATION_MODEL LEFT OUTER JOIN
dbo.SRT_ItemNumbers ON dbo.DM_TBL_CONFIGURATION_MODEL.con_model = dbo.SRT_ItemNumbers.ITEM_NUMBER LEFT OUTER JOIN
dbo.SRT_Data ON dbo.SRT_ItemNumbers.ID = dbo.SRT_Data.ITEM_NUMBER_ID
WHERE (SRT_Data.id) IN
( SELECT MAX(id)
FROM SRT_Data
)
and con_model='model'
If you want one row, use TOP (1):
SELECT TOP (1) cm.con_model, s.SRT_VALUE_CURRENT, cm.con_id, s.ID, s.PROD_MONTH
FROM dbo.DM_TBL_CONFIGURATION_MODEL cm LEFT OUTER JOIN
dbo.SRT_ItemNumbers i
ON cmL.con_model = i.ITEM_NUMBER LEFT OUTER JOIN
dbo.SRT_Data s
ON i.ID = s.ITEM_NUMBER_ID
WHERE cm.con_model = 'model'
ORDER BY s.prod_month DESC;
I am using Cross Apply.
SELECT *
FROM dbo.DM_TBL_CONFIGURATION_MODEL a CROSS APPLY
(
Select Top 1 b.ID,dbo.SRT_Data.SRT_VALUE_CURRENT
From dbo.SRT_ItemNumbers b LEFT OUTER JOIN
dbo.SRT_Data ON b.ID = dbo.SRT_Data.ITEM_NUMBER_ID
Where b.ITEM_NUMBER = a.con_model
Order By ID Desc
) X

Nesting queries on JOINS and top1 with ties

I am trying to use the result of the below SQL query-1 such that I can make another JOIN on this with my second query result to retrieve Fundsrc on the common ID - Project.
QUERY 1-
SELECT top 1 with ties
t.project, r.rel_value AS "FundSrc" ,r.date_to
from atsproject t
LEFT OUTER JOIN aglrelvalue r ON(t.client=r.client AND r.rel_attr_id='ZB18' AND r.attribute_id='B0' AND t.project=r.att_value)
WHERE r.date_To > '04/30/2020' and status='n'
ORDER BY row_number() over (partition by t.project order by t.project, r.rel_value)
I cannot put the JOIN inside the above query as it will mess with the result. Instead, if I can do a nesting on this then I think that should solve the issue.
My second query is -
SELECT
t.project,t.work_order as activity, r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1 ON( t.work_order = r1.dim_value AND t.client = r1.client AND r1.attribute_id = 'BF')
WHERE t.client='PC' and t.status = 'N'
The Output should be -
t.project,t.work_order from query 2 + Fundsrc from Query 1, with the common id on Project ID.
Any suggestions on this is highly appreciated.
You can wrap 'subqueries' in parenthesis and then join them.
Can you try this?:
SELECT *
FROM (
SELECT top 1 with ties t.project,
r.rel_value AS "FundSrc",
r.date_to
FROM atsproject t
LEFT OUTER JOIN aglrelvalue r
ON t.client=r.client
AND r.rel_attr_id='ZB18'
AND r.attribute_id='B0'
AND t.project=r.att_value
WHERE r.date_To > '04/30/2020' and status='n'
ORDER BY row_number() over (partition by t.project order by t.project, r.rel_value)
) AS TABLE_1
LEFT JOIN
(
SELECT t.project,
t.work_order as activity,
r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1
ON t.work_order = r1.dim_value
AND t.client = r1.client
AND r1.attribute_id = 'BF'
WHERE t.client='PC' and t.status = 'N'
) AS TABLE_2
ON TABLE_1.PROJECT = TABLE2.PROJECT
I am pretty sure an ORDER BY clause will not work within a subquery. Thus, this should probably work:
SELECT *
FROM (
SELECT t.project,
r.rel_value AS "FundSrc",
r.date_to,
row_number() over (partition by t.project order by t.project, r.rel_value) AS MY_RANKING
FROM atsproject t
LEFT OUTER JOIN aglrelvalue r
ON t.client=r.client
AND r.rel_attr_id='ZB18'
AND r.attribute_id='B0'
AND t.project=r.att_value
WHERE r.date_To > '04/30/2020' and status='n'
) AS TABLE_1
LEFT JOIN
(
SELECT t.project,
t.work_order as activity,
r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1
ON t.work_order = r1.dim_value
AND t.client = r1.client
AND r1.attribute_id = 'BF'
WHERE t.client='PC' and t.status = 'N'
) AS TABLE_2
ON TABLE_1.PROJECT = TABLE2.PROJECT
WHERE TABLE_1.MY_RANKING = 1
Note: On your formatting, wrap words within ` when they refer to code. They will look like this.
Wrap blocks of code within three of those (three at the beginning and at the end). It will look like the blocks of code above.

Query for records count from shown rows

select lsd.lsd ,count(reading.infrastructure_id),type.infrastructure_type from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
Make the query as an in-line view and select count(*) from the in-line view
Eg:
select count(*) from(
select lsd.lsd
,count(reading.infrastructure_id)
,type.infrastructure_type
from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
)x

SQL Join SELECT MAX, But also where a value does not exist

I have the following SQL which works - It displays all of the items, along with the MAX starttime.
However, I'd also like to show items that to not have a record in playlistlog - How would one
SELECT items.idx, items.title, items.artist, playlistlog.starttime
FROM items
LEFT JOIN playlistlog ON playlistlog.item = items.idx
WHERE playlistlog.starttime = (
SELECT MAX(starttime)
FROM playlistlog AS pl2
WHERE pl2.item = items.idx
)
The where clause is turning your left join into an inner join.
Use AND instead of WHERE.
SELECT items.idx, items.title, items.artist, playlistlog.starttime
FROM items
LEFT JOIN playlistlog ON playlistlog.item = items.idx
and playlistlog.starttime = (
SELECT MAX(starttime)
FROM playlistlog AS pl2
WHERE pl2.item = items.idx
)
This can be done a bit shorter using standard SQL's window function:
SELECT items.idx, items.title, items.artist, pl.starttime
FROM items
LEFT JOIN (
select item,
starttime,
row_number() over (partition by item order by starttime desc) as rn
from playlistlog
) pl ON pl.item = items.idx AND pl.rn = 1

Limiting result sets by future date - SQL

The Query below produces a record for each Entry in the SP_ScheduleEvent Table.
SELECT m.MaterialId, m.MaterialTitle, se.EventDateTime, c.ChannelName
FROM GB_Material m
LEFT OUTER JOIN SP_ScheduleEvent se on se.MaterialName = m.MaterialName
INNER JOIN SP_Schedule s on s.ScheduleID = se.ScheduleID
INNER JOIN GB_Channel c on c.ChannelID = s.ChannelID
WHERE LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%'
I want to limit the result set by the nearest future EventDateTime.
So per material name i would like to see one EventDateTime, which should be the nearest future date to the current time.
And lastly, a record may not exist in the SP_ScheduleEvent table for a particular materialname, in which case there should be null returned for the EventDateTime column
SQLFiddle
How would i go about doing this?
First, your LEFT JOIN is immaterial, because the subsequent joins make it an INNER JOIN. Either use LEFT JOIN throughout the FROM statement or switch to INNER JOIN.
I think you can use ROW_NUMBER():
SELECT t.*
FROM (SELECT m.MaterialId, m.MaterialName, m.MaterialTitle, se.EventDateTime,
ROW_NUMBER() over (PARTITION BY m.MaterialId OVER se.EventDateTime DESC) as seqnum
FROM GB_Material m INNER JOIN
SP_ScheduleEvent se
on se.MaterialName = m.MaterialName INNER JOIN
SP_Schedule s
on s.ScheduleID = se.ScheduleID INNER JOIN
GB_Channel c
on c.ChannelID = s.ChannelID
WHERE se.EventDateTime > getdate() AND
(LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%')
) t
WHERE seqnum = 1
ORDER BY se.EventDateTime;
Use the ROW_NUMBER() function:
WITH cte AS (
SELECT m.MaterialId, m.MaterialTitle, se.EventDateTime, c.ChannelName,
ROW_NUMBER() OVER (PARTITION BY m.MaterialId ORDER BY EventDateTime ASC) AS rn
FROM GB_Material m
LEFT OUTER JOIN SP_ScheduleEvent se on se.MaterialName = m.MaterialName
LEFT OUTER JOIN SP_Schedule s on s.ScheduleID = se.ScheduleID
LEFT OUTER JOIN GB_Channel c on c.ChannelID = s.ChannelID
WHERE LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%'
AND se.EventDateTime > GETDATE()
)
SELECT * FROM cte
WHERE rn=1