SQL: Adding another MAX field to existing MAX Date Query - sql

I have an existing query that is picking up the max date of the exdt field per below for every record for that particular item. I'm trying to add an additional MAX calculation to the sqn field, essentially picking up records with the highest exdt and sqn field together. I tried adding an additional "AND (a.sqn = (SELECT MAX(sqn) to the WHERE and it seems to not like multiple selects.
SELECT a.item, a.cpc, dt.dsc, a.exdt, a.sqn
FROM dbo.ct AS a INNER JOIN dbo.dt ON a.cpc = dt.cpc
WHERE (a.exdt = (SELECT MAX(exdt) AS exdt FROM dbo.ct AS a
Any help would be appreciated!
Thanks.

The script to get records having max of both fields is the following
SELECT a.item, a.cpc, dt.dsc, a.exdt, a.sqn
FROM dbo.ct AS a INNER JOIN dbo.dt ON a.cpc = dt.cpc
WHERE
a.exdt = (SELECT MAX(exdt) AS exdt FROM dbo.ct )
and
a.sqn= (SELECT MAX(sqn) AS exdt FROM dbo.ct)
You can also use CTEas follows
with
cte_principal as
(SELECT a.item, a.cpc, dt.dsc, a.exdt, a.sqn
FROM dbo.ct AS a INNER JOIN dbo.dt ON a.cpc = dt.cpc),
cte_max_exdt as (SELECT MAX(exdt) AS exdt FROM dbo.ct),
cte_max_sqn as (SELECT MAX(sqn) AS exdt FROM dbo.ct)
select p.* from cte_principal p
inner join cte_max_exdt on p.exdt =cte_max_exdt.exdt
inner join cte_max_sqn pn p.sqn=cte_max_sqn.sqn

Perhaps you need subquery which is going to find max date for each item.
That is ct_max_date in my case
After that you join that subquery by max_date and item_Id
SELECT a.item, a.cpc, dt.dsc, a.exdt, a.sqn
FROM dbo.ct AS a
INNER JOIN dbo.dt ON a.cpc = dt.cpc
inner join (
select max(exdt) as max_date, ct.cpc
from dbo.ct
group by ct.dt
) as ct_max_date on a.cpc=ct_max_date.cpc and a.exdt=ct_max_date.max_date

Related

Take only rows with fields MAX date

I have following query:
SELECT cl.[Name] Client, bt.Name BottleType, SUM(csi.Amount) Amount
FROM T_Clients cl
INNER JOIN T_ClientStore cs ON cs.FK_ClientId = cl.ClientID
INNER JOIN T_ClientStoreItem csi ON csi.FK_ClientStoreId = cs.ClientStoreId
INNER JOIN T_BottleType bt ON bt.BottleTypeId = csi.FK_BootleTypeID
GROUP BY cl.[Name], bt.Name
ORDER BY cl.[Name]
In the T_ClientStore table there is column DueDate. I want to take only the records grouped by cl.[Name] for MAX(DueDate). Where could i define that? Somethin like to add:
WHERE cs.DueDate is MAX
Starting from your existing query and based on your description, a straight-forward approach would be to just turn the join on T_ClientStore to a lateral join, which retrieves the latest record for the given client:
SELECT cl.[Name] Client, bt.Name BottleType, SUM(csi.Amount) Amount
FROM T_Clients cl
CROSS APPLY (
SELECT TOP(1) *
FROM T_ClientStore cs
WHERE cs.FK_ClientId = cl.ClientID
ORDER BY cs.DueDate DESC
) cs
INNER JOIN T_ClientStoreItem csi ON csi.FK_ClientStoreId = cs.ClientStoreId
INNER JOIN T_BottleType bt ON bt.BottleTypeId = csi.FK_BootleTypeID
GROUP BY cl.[Name], bt.Name
ORDER BY cl.[Name]

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.

How to display distinct values based on MAX date in report builder?

I'm quite new to SQL and I hope you can help me.
I'm trying to retrieve unique values from my table based on the latest date where specific users are selected.
This is the data:
Raw Data
And this is what I'm looking to achieve:
Desired Data
I tried to write 2 queries but unfortunately:
My 1st query would display duplicated rows for each company:
SELECT DISTINCT FilteredAppointment.regardingobjectidname ,FilteredAppointment.owneridname ,FilteredAppointment.subject ,MAX(FilteredAppointment.scheduledstart) as Date ,FilteredAppointment.location ,FilteredCcx_member.ccx_mnemonic FROM FilteredAppointment INNER JOIN FilteredAccount ON FilteredAppointment.regardingobjectid = FilteredAccount.accountid INNER JOIN FilteredCcx_member ON FilteredAccount.accountid = FilteredCcx_member.ccx_accountid WHERE FilteredAppointment.statecodename != N'Canceled' AND FilteredAppointment.owneridname IN (N'User1', N'User2', N'User3') GROUP BY FilteredAppointment.regardingobjectidname ,FilteredAppointment.owneridname ,FilteredAppointment.subject ,FilteredAppointment.scheduledstart ,FilteredAppointment.location ,FilteredCcx_member.ccx_mnemonic ORDER BY FilteredAppointment.regardingobjectidname
And my 2nd query would display one row only:
SELECT DISTINCT FilteredAppointment.regardingobjectidname ,FilteredAppointment.owneridname ,FilteredAppointment.subject ,FilteredAppointment.scheduledstart ,FilteredAppointment.location ,FilteredCcx_member.ccx_mnemonic FROM FilteredAppointment INNER JOIN FilteredAccount ON FilteredAppointment.regardingobjectid = FilteredAccount.accountid INNER JOIN FilteredCcx_member ON FilteredAccount.accountid = FilteredCcx_member.ccx_accountid WHERE FilteredAppointment.scheduledstart = (SELECT MAX(FilteredAppointment.scheduledstart) FROM FilteredAppointment WHERE FilteredAppointment.regardingobjectidname = FilteredAppointment.regardingobjectidname) AND FilteredAppointment.statecodename != N'Canceled' AND FilteredAppointment.owneridname IN (N'User1', N'User2', N'User3') GROUP BY FilteredAppointment.regardingobjectidname ,FilteredAppointment.owneridname ,FilteredAppointment.subject ,FilteredAppointment.scheduledstart ,FilteredAppointment.location ,FilteredCcx_member.ccx_mnemonic ORDER BY FilteredAppointment.regardingobjectidname
Try this:-
SELECT distinct a.date, a.company, a.companyID, a.User, a.Location, a.topic
FROM tablename a
inner join
(
Select company, companyID, User, max(date) as recent_date
from
tablename
group by company, companyID, User
) b
on a.date=b.recent_date and a.company=b.company and a.companyID=b.companyID
and a.User=b.User;
I managed to solve the issue - Thank you for the help again!
WITH apptmts AS (SELECT TOP 1 WITH TIES fa.scheduledstart,fa.location,fa.regardingobjectidname,mem.ccx_mnemonic,fa.owneridname,fa.subject FROM FilteredAppointment fa JOIN FilteredAccount acc on fa.regardingobjectid = acc.accountid JOIN FilteredCcx_member mem ON acc.accountid = mem.ccx_accountid WHERE fa.statecodename != N'Canceled' AND fa.owneridname IN (N'User1', N'User2', N'User3') ORDER BY ROW_NUMBER() OVER(PARTITION BY fa.regardingobjectidname ORDER BY fa.scheduledstart DESC) ) SELECT * FROM apptmts ORDER BY scheduledstart DESC

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

Combine three SQL queries

I'm trying to fetch data for my forum's index. Fetching a list of all the boards, the number of threads in that board, and the number of posts for each of those threads in that board.
SELECT
board.*,
IFNULL(a.thread_count, 0) AS thread_count,
b.post_count
FROM
(SELECT * FROM r_forum_boards ORDER BY position) board
LEFT OUTER JOIN
(SELECT r_forum_threads.board, r_forum_threads.id,
COUNT(r_forum_threads.id) AS thread_count
FROM r_forum_threads) a
ON board.id = a.board
LEFT OUTER JOIN
(SELECT r_forum_posts.thread_id, COUNT(*) AS post_count
FROM r_forum_posts) b
ON b.thread_id = a.id
The problem is that post_count is returning NULL. I've tried a few different variations of this, but none of them are working.
I'm guessing from the IFNULL that your SQL is MySQL-flavored. In that case, you can use COUNT DISTINCT to simplify things.
SELECT
board.id,
COUNT(DISTINCT r_forum_threads.id) AS thread_count,
COUNT(r_forum_posts.id) AS post_count
FROM board
LEFT OUTER JOIN r_forum_threads ON board.id = r_forum_threads.board
LEFT OUTER JOIN r_forum_posts ON r_forum_posts.thread_id = r_forum_threads.id
GROUP BY board.id
ORDER BY board.position
Depending on how much of board.* you actually need, either add columns to the SELECT and GROUP or use this as a subquery to join back to board.
Try putting in a GROUP clause:
LEFT OUTER JOIN
(SELECT r_forum_threads.board, r_forum_threads.id, COUNT(r_forum_threads.id) AS thread_count FROM r_forum_threads GROUP BY r_forum_threads.id) a
ON board.id = a.board
LEFT OUTER JOIN
(SELECT r_forum_posts.thread_id, COUNT(*) AS post_count FROM r_forum_posts GROUP BY r_forum_posts.thread_id) b ON b.thread_id = a.id
See if that does the trick.
Perhaps because you are missing the Group By clause in your subqueries? In addition, you do not need the first subquery.
Select board...
, Coalesce(a.thread_count, 0) AS thread_count
, b.post_count
From r_forum_boards
Left Join (
Select r_forum_threads.board
, r_forum_threads.id
, Count(r_forum_threads.id) AS thread_count
From r_forum_threads
Group By r_forum_threads.board
, r_forum_threads.id
) a
On a.board = board.id
Left Join (
Select r_forum_posts.thread_id
, Count(*) AS post_count
From r_forum_posts
Group By r_forum_posts.thread_id
) As b
On b.thread_id = a.id
Order By r_forum_boards.position
You might consider changing the query slightly to make it easier to test:
Select board...
, Coalesce(a.thread_count, 0) AS thread_count
, A.post_count
From r_forum_boards
Left Join (
Select r_forum_threads.board
, r_forum_threads.id
, Count(r_forum_threads.id) AS thread_count
, Posts.post_count
From r_forum_threads
Left Join (
Select r_forum_posts.thread_id
, Count(*) AS post_count
From r_forum_posts
Group By r_forum_posts.thread_id
) As Posts
On Posts.thread_id = r_forum_threads.Id
Group By r_forum_threads.board
, r_forum_threads.id
) As A
On A.board = board.id
Order By r_forum_boards.position
In this way, you can run the single inner query and ensure you A. get results and B. get values for post_count.
The problem I see is that you're trying to get 2 related but slightly conflicting pieces of data, and probably 2 queries will get you what you need.
You first need a query to get the board names and the number of threads in each board.
Select Board.*, GroupThread.threadCount
FROM r_forum_boards Board
INNER JOIN (Select board_id, count(*) as threadCount from r_forum_threads group by board_id) GroupThread ON Board.board_id = GroupThread.board_id
Second, for each thread, you need the posts, which are calculated in basically the same way:
Select Thread.*, GroupPosts.postCount
FROM r_forum_threads Thread
INNER JOIN (Select thread_id, count(*) as postCount from r_forum_posts group by thread_id) GroupPosts ON Thread.board_id = GroupPosts.thread_id
In each of these cases, you look at the parent object, and count the children.